以後一定要細心,不能再犯這個低級的錯誤,把WA控制在最低範圍內
參考了 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,則需要輸出一行資訊。
Source Code
| Problem: 1033 |
|
User: yangliuACMer |
| Memory: 420K |
|
Time: 704MS |
| Language: C++ |
|
Result: Accepted |
#include <iostream>#include <stack>using namespace std;int clusters[10001];int clusters_num, file_num;int counter = 1, move_num = 0;//檔案片段的其實編號和操作的總數int next, i, j, t, n;stack<int> s;void deal(){while(!s.empty()){t = s.top();cout<<t<<" "<<next<<endl;clusters[next] = clusters[t];next = t;s.pop();move_num++;}}void work(){for(i = 1; i <= clusters_num; i++){if(clusters[i] == i){//剛好放在了目標位置,無需移動continue;}else if(clusters[i] != 0){s.push(i);next = clusters[i];bool is_circled = false;//下面判斷是否出現了環while(true){if(clusters[next] == i){is_circled = true;break;} else if(clusters[next] == 0){is_circled = false;break;}s.push(next);next = clusters[next];//有用數組模仿鏈表的思想}if(is_circled == true){//有環的情況for(j = clusters_num; j >=0; j--){if(clusters[j] == 0) break;//從後向前找一個空位置,為解開環做準備}cout<<next<<" "<<j<<endl;clusters[j] = clusters[next];deal();clusters[next] = clusters[j];//把開始的結點移動回去clusters[j] = 0;cout<<j<<" "<<next<<endl;} else {//沒有環的情況deal();clusters[next] = 0;}}}if(move_num == 0) cout<<"No optimization needed"<<endl;//開始因為輸出格式中needed寫成need 而WA一次,太粗心了!!!}int main(){cin>>clusters_num>>file_num;for(i = 0; i < file_num; i++){cin>>n;for(j = 0; j < n; j++){cin>>t;clusters[t] = counter++;}}work();return 0;}