题解转自:http://www.cnblogs.com/damacheng/archive/2010/09/24/1833983.html
题目大意:你要写一个OS,要实现磁盘碎片整理的功能。磁盘分为N个簇,一个文件可以占用K个簇,(1 <= K < N <= 10000),给出各个文件的占用磁盘的情况,也就是一个文件占用了哪些簇,想要进行碎片整理,就是把这些簇按顺序整理到磁盘的最顶部,例如给出示例:
文件1:2 3 11 12,占用了4个簇,编号为1-4。
文件2:7,占用了1个簇,编号为5。
文件3:18 5 10,占用了3个簇,编号为6-8。
初始状态是这样的,0表示未占用:
簇号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
逻辑编号:0 1 2 0 7 0 5 0 0 8 3 4 0 0 0 0 0 6
一共整理到最后,磁盘的情况最后是这样的:
簇号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
逻辑编号:1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 0 0
写一个程序得到整理好碎片最少需要多少步操作,并把这些操作打印出来。比如说第1个簇的内容放到第2个簇,打印出1 2。操作的定义是这样的:把一个簇的内容放到另个一个簇中,算是一步操作。
注意这里是Special Judge,意思是只要答案符合要求就行了,不必和SAMPLE中的OUTPUT一样也可以AC。
怎么才能找到最少的步数呢?我想了半天也没怎么想出来,于是看了看DISCUSS,总结以下:
遍历整个磁盘,设i为当前遍历的簇的编号,clusters为整个磁盘,clusters[i]表示第i个簇是否被占用,被哪个编号的文件片段占据。
(1) 如果clusters[i]为0,也就是未被使用,不进行处理。
(2) 如果clusters[i]为i,也就是已经到了整理好的状态,不进行处理。
(3) 如果clusters[i]不满足1和2,则又有两种情况。
情况一:磁盘使用情况成链:如图所示:
簇号: 1 2 3 4 5 6 ...
逻辑编号:5 0 4 2 3 0 ...
第1个簇被第5个文件片断占据,第5个簇又被第3个文件片段占据,第3个簇又被第4个文件片段占据,第4个簇又
被第2个文件片断占据,第2个簇未被占据。算法就很简单了,按照簇被访问的反方向:
clusters[2] = clusters[4],clusters[4] = clusters[3],clusters[3] = clusters[5],
clusters[5] = clusters[1],最后clusters[1] = 0。怎么样反方向呢,使用一个栈就好了。
情况二:磁盘使用情况成环:如图所示:
簇号: 1 2 3 4 5 6 ...
逻辑编号:5 1 4 2 3 0 ...
这种情况跟情况一差不多,只是最后clusters[2]指向了第1个簇,这样就形成了一个环,这里只是需要额外的
处理一下,就像交换2个变量一样,先在从磁盘末尾找到1个空的簇,因为题目保证至少有一个空的簇,先把
clusters[2]放到这个空的簇中,然后再执行情况1中的操作,最后再把空的簇的值赋给clusters[1]就好了。
最后注意一点,如果操作次数为0,则需要输出一行信息。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorithm> 8 #include<map> 9 #include<iomanip> 10 #include<climits> 11 #include<string.h> 12 #include<numeric> 13 #include<cmath> 14 #include<stdlib.h> 15 #include<vector> 16 #include<stack> 17 #include<set> 18 #define FOR(x, b, e) for(int x=b;x<=(e);x++) 19 #define REP(x, n) for(int x=0;x<(n);x++) 20 #define INF 1e7 21 #define MAXN 100010 22 #define maxn 1000010 23 #define Mod 1000007 24 #define N 1010 25 using namespace std; 26 typedef long long LL; 27 28 int n, m; 29 int c[10010]; 30 int tmp; 31 int k; 32 int num; 33 34 void gao() 35 { 36 int next; 37 num = 0; 38 stack<int> s; 39 for (int i = 1; i <= n; ++i) { 40 if (c[i] == i || c[i] == 0) continue; 41 s.push(i); 42 next = c[i]; 43 bool is_circle = false; 44 while (true) { 45 if (c[next] == i) { //比如3放5 5放3,形成了一个环 46 is_circle = true; 47 break; 48 } 49 else if (c[next] == 0) { 50 is_circle = false; 51 break; 52 } 53 s.push(next); 54 next = c[next]; 55 } 56 int j; 57 if (is_circle == true) { 58 for (j = n; j >= 1; --j) 59 if (c[j] == 0) break; 60 printf("%d %d\n", next, j); 61 c[j] = c[next]; 62 while (!s.empty()) { 63 int t = s.top(); 64 s.pop(); 65 printf("%d %d\n",t,next); 66 c[next] = c[t]; 67 next = t; 68 num++; 69 } 70 c[next] = c[j]; 71 c[j] = 0; 72 printf("%d %d\n", j, next); 73 } 74 else { 75 while (!s.empty()) { 76 int t = s.top(); 77 s.pop(); 78 printf("%d %d\n", t, next); 79 c[next] = c[t]; 80 next = t; 81 num++; 82 } 83 c[next] = 0; 84 } 85 } 86 if (num == 0) puts("No optimization needed"); 87 } 88 89 int main() 90 { 91 int tt; 92 cin >> n >> m; 93 k = 1; 94 for (int i = 0; i < m; ++i) { 95 cin >> tmp; 96 for (int i = 0; i < tmp; ++i) { 97 cin >> tt; 98 c[tt] = k++; 99 } 100 } 101 gao(); 102 return 0; 103 }