题意:初始状态为左边空一行,数字在右边28个格子。末态要按一副卡片在一行顺序牌,即第一行为11-17,第二行21-27,。。。。,可以通过四个空格来转移卡片,问从初始状态到末态最少要多少步。
分析:
1、每次操作只能把一个数字放到某个空格,不能交换两个数字的位置。
2、用的是再哈希法hash =(v+10)%M来处理冲突。
3、空格的左边为空或者数字的末尾为7则不能填充。
4、填充空格要找比他左边大1的数来填充。
#include<iostream> #include<queue> using namespace std; #define MOD 1000007 __int64 Hash[1000007]; //hash表,用于hash判重 struct Node { int map[4][8]; //图 int step; //步数 bool operator==(const Node& p)const //判断相等 { int i,j; for(i=0;i<4;i++) for(j=0;j<8;j++) if(map[i][j]!=p.map[i][j]) return false; return true; } __int64 HashValue() //hash值 { __int64 v=0; int i,j; for(i=0;i<4;i++) for(j=0;j<8;j++) v+=(v<<1)+map[i][j]; return v; } }; Node s,e; //初始节点和结束节点 void Swap(int& a,int& b) { int tmp; tmp=a; a=b; b=tmp; } void Read() { int i,j; memset(Hash,-1,sizeof(Hash)); for(i=0;i<4;i++) //初始第0列为空 { s.map[i][0]=0; for(j=1;j<8;j++) scanf("%d",&s.map[i][j]); } s.step=0; } void GetEnd() //获得终态 { int i,j; for(i=0;i<4;i++) { e.map[i][7]=0; for(j=0;j<7;j++) e.map[i][j]=(i+1)*10+(j+1); } } bool HashJudge(__int64 value) //hash判重 { int v; v=value%MOD; while(Hash[v]!=-1 && Hash[v]!=value) //冲突处理,在hash法 { v+=10; v%=MOD; } if(Hash[v]==-1) { Hash[v]=value; return true; } return false; } bool bfs(int& ans) { queue<Node> q; Node p,p2; int i,j,x,y,value,k,l; bool fg; __int64 ha; q.push(s); //初始节点入队 HashJudge(s.HashValue()); while(!q.empty()) { p=q.front(); q.pop(); for(i=0;i<4;i++) for(j=0;j<8;j++) { if(!p.map[i][j]) //格子为空 { p2=p; p2.step++; value=p.map[i][j-1]+1; //找比map[i][j-1]大1的数 if(value==1||value%10==8) //0或者value为7的不能移动 continue; fg=true; for(k=0;k<4&&fg;k++) for(l=1;l<8&&fg;l++) if(p.map[k][l]==value) { x=k; y=l; fg=false; } if(!fg) { Swap(p2.map[i][j],p2.map[x][y]); ha=p2.HashValue(); if(HashJudge(ha)) //hash判重 { if(p2==e) { ans=p2.step; return true; } q.push(p2); } } } } } return false; } void Process() { int k,i,j,ans; k=0; for(i=0;i<4;i++) //初始时将11,21,31,41移动到第0列 for(j=1;j<8;j++) if(s.map[i][j]==(k+1)*10+1) { Swap(s.map[i][j],s.map[k][0]); k++,i=0,j=0; } if(s==e) { cout<<0<<endl; //前四步不记录 return ; } if(bfs(ans)) cout<<ans<<endl; else cout<<-1<<endl; } int main() { int T; scanf("%d",&T); GetEnd(); while(T--) { Read(); Process(); } return 0; }
时间: 2024-10-24 01:41:08