You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 16; // 1≤n≤15
int a[N]; // 记录书的排列情况
int n; // 书的数量
int depth; // 最少的操作步数
// 估值函数:实时计算此状态到终止状态最少的步数
// 这个IDA*的估价函数本质上与A*的是一样的意思都是在每个状态下可以获取到距离理想状态即每个数字后序都大1的错误后继个数
int f() {
int cnt = 0;
// 计算前后非+1递增的 错误后继的对数
for (int i = 0; i < n - 1; i++)
if (a[i] + 1 != a[i + 1]) cnt++;
return (cnt + 2) / 3; // 每次移动最多能解决三个错误后继如果现在有cnt个错误后继最少需要 ⌈cnt/3⌉次操作
}
// u:已经操作的步数
bool dfs(int u) {
int t = f(); // 未来最小的操作步数
if (t == 0) return true; // 已完成排序
if (u + t > depth) return false; // 当前操作步数+未来预期最小> 迭代加深的深度 表示没有找到结果,返回。及时剪枝
for (int len = 1; len < n; len++) { // 枚举抽取长度 len∈[1,n-1)
// st: 起始下标
// st ∈ [0,n-1] 左边界很好理解现在看一下右边界st+len也就是终止坐标不能大于n-1
for (int st = 0; st + len < n; st++) {
// ed:结束下标
// 注意只考虑右移不考虑左移因为这是一个对称的操作A串向B串后面右移相当于B串向A串前面左移
for (int ed = st + len; ed < n; ed++) {
// 序列右移
// reverse():这是一个前闭后开的区间[),时刻要提醒自己注意!
reverse(a + st, a + st + len);
reverse(a + st + len, a + ed + 1);
reverse(a + st, a + ed + 1);
// 本轮实现了一次右移,那么,这条路线是否可以成功抵达终点,就依赖于我的后续子孙了
if (dfs(u + 1)) return true;
// 后面串的长度,还原现场,回溯
reverse(a + st, a + ed - len + 1);
reverse(a + ed + 1 - len, a + ed + 1);
reverse(a + st, a + ed + 1);
}
}
}
return false;
}
// AC 204 ms
int main() {
int T; // T组测试数据
scanf("%d", &T);
while (T--) {
scanf("%d", &n); // 表示书的数量
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
/*
最少操作次数
解释因为可能书本来天生就是有序即每本书n后面都是n+1完全合格的顺序这时不用调整最少操作数为0
需要从0开始查询最少操作次数
*/
depth = 0;
while (depth < 5 && !dfs(0)) depth++; // 有层数限制的dfs迭代加深
if (depth >= 5) // 最少操作次数大于或等于5次
puts("5 or more");
else
printf("%d\n", depth); // 最少操作次数
}
return 0;
}