[ACM]磁盘碎片的整理算法

poj 1033 Defragment 解题报告

磁盘整理,按照从第一个文件到最后一个文件的顺序排放,而且每个文件的碎片按原来的顺序放在一起,要求转移的次数最少。

解:

其实根本不用搜索,一开始想搜索想了很久,上网找解题报告也没找到(这么水的一题竟然没有解题报告),于是开始自已想。

其实碎片的排列只有二种情况:

1. A0碎片没有放在原来的位置,而它原来的位置正好是空的。而A1碎片也刚好没有放在原来的位置,而b原来的位置之前一直被A0占领,同样还有A2碎片没有在原来位置,而其原来的位置之前一直被A1占领,以此递推直到Ai,没有碎片要放在Ai的位置为止。这种情况称为链。

2. 基本上同1一样,不过,一开始的时候A0的原来位置并不是空的,而是最后的那个Ai占领着,这种情况称为环。

解决方法:

1。对于1,只需要从A0开始一个一个按顺序放到原来的位置上即可。

2。对于2,只需要从环中的任何一个节点开始,先将这个节点放到从尾部开始数起的空位,然后以链的方式处理,最后再将这个节点的数放回到最后一个节点的位置。

主要数据结构:

q[i]:放在第i个位上的数应该放在第q[i]个位上。

d[i]:应该放在第i个位上的数,现在放在了第d[i]个位上。

PS:这是本人除了1000之外第一次一击即AC的题,特上来发一篇解题报告庆祝!~

附AC 代码:

#include <iostream>
using namespace std;

int n,k,tmp,t,index,pi;
int q[10000];
int d[10000];
bool optneed;

int main(){
 optneed=false;
 memset(q,-1,10000*sizeof(int));
 memset(d,-1,10000*sizeof(int));
 scanf("%d%d",&n,&k);
 int counter=0;
 for(int j=0;j<k;j++){
 scanf("%d",&t);
 for(int i=0;i<t;i++){
  scanf("%d",&tmp);
  tmp--;
  q[tmp]=counter;
  d[counter]=tmp;
  counter++;
 }
 }

 //put nodes whose correct place is empty and solve the chains.
 for(int i=0;i<n;i++){
  if(q[i]==i||q[i]==-1) continue;
  optneed=true;
  if(q[q[i]]==-1){
  printf("%d %d\n",i+1,q[i]+1);
  q[q[i]]=q[i];q[i]=-1;
  index=i;
  while(d[index]!=-1){
  printf("%d %d\n",d[index]+1,index+1);
  q[d[index]]=-1;q[index]=index;
  index=d[index];
  }
  continue;
  }
 }
 if(optneed==true){
 //solve the rings
 for(int i=0;i<n;i++){
  if(q[i]==i||q[i]==-1) continue;
  index=i;
  for(tmp=n-1;tmp>=0;tmp--) if(q[tmp]==-1) break;
  printf("%d %d\n",i+1,tmp+1);
  q[tmp]=q[i];q[index]=-1;
  while(index!=q[tmp]){
  printf("%d %d\n",d[index]+1,index+1);
  q[index]=index;q[d[index]]=-1;
  index=d[index];
  }
  printf("%d %d\n",tmp+1,index+1);
  q[index]=q[tmp];q[tmp]=-1;
 }
 }else printf("No optimization needed\n");


 return 0;
}

posted @ 2009-09-30 12:22  梁星  阅读(2163)  评论(0编辑  收藏  举报
Mobile and Web Analytics