【POJ】【1033】【Defragment】【模拟】解题报告

  地址:http://acm.pku.edu.cn/JudgeOnline/problem?id=1033

  点评:此题的通过率看起来挺吓人的,其实也不难。

  题目大意:你要写一个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,则需要输出一行信息。

 

  最后的最后附上代码:

  Run ID  User         Problem Result   Memory Time  Language Code  Length Submit Time
  7660511 damacheng009 1033    Accepted 324K   250MS C++      2342B 2010-09-24 15:35:35

  

  
  
1 #include < cstdio >
2 #include < stack >
3
4 using std::stack;
5
6 int clusters[ 10001 ]; // 簇的使用情况
7 int cluster_num, file_num; // 簇的总数和文件个数
8 int counter = 1 ; // 文件片段起始编号
9 int mov_num = 0 ; // 操作总数
10 stack < int > s;
11
12 // 过程详见博客讲解
13 void work() {
14 int next;
15
16 for ( int i = 1 ; i <= cluster_num; ++ i) {
17 if (clusters[i] == i) {
18 continue ;
19 } else if (clusters[i] != 0 ) {
20 s.push(i);
21 next = clusters[i];
22
23 bool is_circle = false ;
24 while ( true ) {
25 if (clusters[next] == i) {
26 is_circle = true ;
27 break ;
28 } else if (clusters[next] == 0 ) {
29 is_circle = false ;
30 break ;
31 }
32
33 s.push(next);
34 next = clusters[next];
35 }
36
37 int t, j;
38 if (is_circle == true ) {
39 for (j = cluster_num; j >= 0 ; -- j) {
40 if (clusters[j] == 0 ) {
41 break ;
42 }
43 }
44
45 printf( " %d %d\n " , next, j);
46 clusters[j] = clusters[next];
47
48 while ( ! s.empty()) {
49 t = s.top();
50 printf( " %d %d\n " , t, next);
51 clusters[next] = clusters[t];
52 next = t;
53 s.pop();
54 mov_num ++ ;
55 }
56 clusters[next] = clusters[j];
57 clusters[j] = 0 ;
58 printf( " %d %d\n " , j, next);
59 } else {
60 while ( ! s.empty()) {
61 t = s.top();
62 printf( " %d %d\n " , t, next);
63 clusters[next] = clusters[t];
64 next = t;
65 s.pop();
66 mov_num ++ ;
67 }
68
69 clusters[next] = 0 ;
70 }
71 }
72 }
73
74 // 别忘了
75 if (mov_num == 0 ) {
76 printf( " No optimization needed\n " );
77 }
78 }
79
80 int main() {
81 // freopen("e:/data.txt", "r", stdin);
82 scanf( " %d %d " , & cluster_num, & file_num);
83
84 for ( int i = 0 ; i < file_num; ++ i) {
85 int n, t;
86 scanf( " %d " , & n);
87
88 for ( int j = 0 ; j < n; ++ j) {
89 scanf( " %d " , & t);
90 clusters[t] = counter ++ ;
91 }
92 }
93
94 work();
95
96 return 0 ;
97 }
98

 

你可能感兴趣的:(Fragment)