距离从1000处子题,已经过了好些日子了,终于突破20题了,但是还没有进入前1W(中国的人真多啊),一直在做动态规划的题,实在是被动态规划的强大折服。最近开始找些搜索的题来做,剪那个sticks,一直剪不过TLE,于是决定换道题,看网上的推荐说这是一道搜索题,于是开始切!~~~
题意:
磁盘整理,按照从第一个文件到最后一个文件的顺序排放,而且每个文件的碎片按原来的顺序放在一起,要求转移的次数最少。
解:
其实根本不用搜索,一开始想搜索想了很久,上网找解题报告也没找到(这么水的一题竟然没有解题报告),于是开始自已想。
其实碎片的排列只有二种情况:
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;
}