1 条题解
-
0
解题思路:
本问题要求通过最少的转置操作(交换两个连续书块)将书籍序列排序成升序。采用迭代加深的算法解决:
关键步骤:
启发式函数:估算当前状态到目标状态的最小转置次数
迭代加深:从开始逐步增加深度限制
状态转移:枚举所有可能的书块交换操作
剪枝优化:当当前深度 估计值 最大深度时剪枝
C++实现:
#include <bits/stdc++.h> #define ll long long #define io cin.tie(0),cout.tie(0),ios::sync_with_stdio(false) #define ri register int // 寄存器变量优化 using namespace std; const int N = 15; // 最大书籍数量 int n; int a[N], w[5][N]; // a:当前书籍序列, w:保存中间状态 // 启发式函数:估算完成排序所需的最小转置次数 inline int f() { int res = 0; // 遍历序列,统计不符合升序的位置数量 for (ri i = 0; i + 1 < n; i++) if (a[i + 1] != a[i] + 1) // 检查相邻书籍是否连续 res++; // 每轮转置最多修复3个位置,向上取整估算 return (res + 2) / 3; } // DFS搜索:tmp-当前深度, maxs-最大深度限制 inline bool dfs(int tmp, int maxs) { // 剪枝:当前深度+估计值超过限制 if (tmp + f() > maxs) return false; // 成功条件:序列已完全排序 if (f() == 0) return true; // 枚举所有可能的转置操作 for (int l = 0; l < n; l++) // 第一书块起始位置 for (int r = l; r < n; r++) // 第一书块结束位置 for (int k = r + 1; k < n; k++) { // 第二书块结束位置 // 保存当前状态 memcpy(w[tmp], a, sizeof a); int x, y; // 执行转置操作: // 1. 将第二书块(r+1到k)移到l位置 for (x = r + 1, y = l; x <= k; x++, y++) a[y] = w[tmp][x]; // 2. 将第一书块(l到r)接到后面 for (x = l; x <= r; x++, y++) a[y] = w[tmp][x]; // 递归搜索下一层 if (dfs(tmp + 1, maxs)) return true; // 回溯:恢复原始状态 memcpy(a, w[tmp], sizeof a); } return false; } int main() { io; // 加速IO int t; cin >> t; // 测试用例数量 while (t--) { cin >> n; // 读取当前书籍序列 for (int i = 0; i < n; i++) cin >> a[i]; // 迭代加深搜索 int depth = 0; // 当前深度限制 // 深度0~4搜索,找到最小转置次数 while (depth < 5 && !dfs(0, depth)) depth++; // 输出结果 depth >= 5 ? cout << "5 or more" << endl : cout << depth << endl; } return 0; }
- 1
信息
- ID
- 2461
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者