有 n 個連續內存塊,k 個文件各自分為若干有序碎片存放。允許操作 a b:將內存塊 a 的內容移至空塊 b。目標:用最少操作使所有文件碎片按順序從最小編號塊開始連續存放。輸出操作序列。
flag[i] = j 表示位置 i 的碎片應去位置 j;0 表示空閒。#include <cstdio>
#include <cstring>
const int N = 10005;
int n, k, flag[N], num;
bool judge() {
for (int i = 1; i <= num; ++i)
if (flag[i] != i) return false;
return true;
}
void solve() {
int c = 0;
while (true) {
int cc = c;
for (int i = 1; i <= num; ++i) {
if (!flag[i]) { // 目標位置空閒
for (int j = 1; j <= n; ++j)
if (flag[j] == i) {
printf("%d %d\n", j, i);
flag[i] = i; flag[j] = 0;
++c; break;
}
}
}
if (c == cc) break; // 本輪無移動
}
}
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &k);
memset(flag, 0, sizeof(flag));
num = 0;
for (int i = 0; i < k; ++i) {
int cnt, pos; scanf("%d", &cnt);
while (cnt--) { scanf("%d", &pos); flag[pos] = ++num; }
}
if (judge()) puts("No optimization needed");
else {
solve();
while (!judge()) {
for (int i = 1; i <= num; ++i)
if (flag[i] && flag[i] != i) {
for (int j = num+1; j <= n; ++j)
if (!flag[j]) {
printf("%d %d\n", i, j);
flag[j] = flag[i]; flag[i] = 0; break;
}
break;
}
solve();
}
}
if (T) puts("");
}
return 0;
}
num 統計碎片總數,只有前 num 個位置是目標區間。flag 兩端:源置 0,目標置目標值。