题意:磁盘n个块,有m个文件,各自被分割成许多块分散在磁盘之中,要求通过最少移动次数使得第1个文件的占1,2,3...f1块,第二个文件占f1+1,f1+2...f1+f2块。。。
题解:dfs(k)为将k位置的文件移到它该去的地方,标记dfs过的点,若发生重复则说明有环,就让当前dfs点移到最大一个空闲块,否则,必定能将链还原。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=10005; 6 int w[N],p[N],n,num;//w[i]:i位置上有一个应该移去w[i]的碎片;p[i]:应该放在i位置的碎片现在的位置 7 bool vis[N]; 8 bool dfs(int k)//把现在在k位置的碎片复原,true代表有环 9 { 10 vis[k]=true; 11 int tp=w[k]; 12 if(w[tp]==0) 13 { 14 printf("%d %d\n",k,tp); 15 w[k]=0; 16 w[tp]=tp; 17 p[tp]=tp; 18 return false; 19 } 20 else if(vis[tp]) 21 { 22 for(int i=n;i>=0;i--) 23 { 24 if(w[i]==0) 25 { 26 printf("%d %d\n",k,i); 27 w[i]=w[k]; 28 w[k]=0; 29 p[w[i]]=i; 30 return true; 31 } 32 } 33 } 34 else 35 { 36 bool flag=dfs(tp); 37 printf("%d %d\n",k,w[k]); 38 w[k]=0; 39 w[tp]=tp; 40 p[tp]=tp; 41 return flag; 42 } 43 } 44 int main() 45 { 46 while(scanf("%d%d",&n,&num)!=EOF) 47 { 48 int pos=1,nu,tp; 49 memset(w,0,sizeof(w)); 50 bool flag=true; 51 for(int i=1;i<=num;i++) 52 { 53 scanf("%d",&nu); 54 for(int j=0;j<nu;j++) 55 { 56 scanf("%d",&tp); 57 w[tp]=pos; 58 p[pos]=tp; 59 if(pos!=tp) 60 flag=false; 61 pos++; 62 } 63 } 64 if(flag) 65 { 66 printf("No optimization needed\n"); 67 continue; 68 } 69 for(int i=1;i<pos;i++) 70 { 71 if(p[i]!=i) 72 { 73 memset(vis,false,sizeof(vis)); 74 if(dfs(p[i])) 75 i--; 76 } 77 } 78 } 79 return 0; 80 }