URAL 1016. Cube on the Walk (分层图+最短路)

来源:互联网 发布:2030中国人工智能 编辑:程序博客网 时间:2024/06/01 08:03


 一个正方体,每个面标了一个数字,问,这个正方体,在8*8的棋盘上,从起点滚动到终点,所有朝下的面的数字之和的最小值(包括起点和终点)。

正方体,经过旋转,最多有24种状态。建立分层图,点数:24*8*8=1536.  稀疏图,用 SPFA 算法求最短路。

我直接写的一维数组。节点编号= 正方体的状态*64 +横坐标*8 +纵坐标 ;

开始求出所有24个状态(特殊情况可能少于24种状态)之间的状态转移。

然后SPFA求最短路。

using namespace std;int dx[4]={-1, 1, 0, 0};int dy[4]={ 0, 0, 1,-1};int de[4]={ 5, 3, 1, 0};struct Dice{int a[6];//按照题目给的顺序,分别为前,后,上,右,下,左 int next[4];//四个方向旋转后的编号void turn(int i){switch(i){case 0:left();break;case 1:right();break;case 2:up();break;case 3:down();break;}}void left(){int t=a[5];a[5]=a[2];a[2]=a[3];a[3]=a[4];a[4]=t;}//向左滚动void right(){int t=a[5];a[5]=a[4];a[4]=a[3];a[3]=a[2];a[2]=t;}//向右滚动void up(){int t=a[0];a[0]=a[4];a[4]=a[1];a[1]=a[2];a[2]=t;}//向上滚动void down(){int t=a[0];a[0]=a[2];a[2]=a[1];a[1]=a[4];a[4]=t;}//向下滚动bool operator ==(const Dice&B)const{int T=0;for(int i=0;i<6;i++) T+=a[i]==B.a[i];return T==6;}void show(){printf("\t(%d,%d,%d,%d,%d,%d)\n",a[0],a[1],a[2],a[3],a[4],a[5]);}}D[24];int Dn;//记录24种状态struct Node{int path;//记录最短路径int Dis;//记录最小值void init(int k){Dis=-1;path=k;}}game[1536];queue<int> Q;bool inq[1536];void Bfs(int k){int tempk=k;int index=tempk/64;tempk%=64;int x=tempk/8,y=tempk%8;for(int i=0;i<4;i++){//向4个方向扩展 int nx=x+dx[i],ny=y+dy[i];int Next=D[index].next[i]*64+nx*8+ny;//计算下个节点的编号 if(nx>=0&&nx<8&&ny>=0&&ny<8){//如果下一点在棋盘内 int Distance=game[k].Dis+D[index].a[de[i]];if(!~game[Next].Dis||Distance<game[Next].Dis){//如果未走过或者路径更短,更新 game[Next].Dis=Distance;game[Next].path=game[k].path;game[Next].path=k;if(!inq[Next]) Q.push(Next),inq[Next]=1;//若未入队,入队 }}}}void F(int i){//输出路径 if(i!=game[i].path) F(game[i].path);int t=i%64;printf(" %c%c",t/8+'a',t%8+'1');}int main(void){//处理输入 string a;int Sx,Sy,Dx,Dy;cin>>a;Sx=a[0]-'a';Sy=a[1]-'1';cin>>a;Dx=a[0]-'a';Dy=a[1]-'1';for(int i=0;i<6;i++) scanf("%d",&D[0].a[i]);//求出24状态之间的状态转移。Dn=1;for(int i=0;i<Dn;i++){//对于每个状态(开始只有一个状态) for(int k=0;k<4;k++){// 向四个方向滚动 Dice temp=D[i];temp.turn(k);//记录滚动后的状态int Target=-1;for(int j=0;j<Dn;j++){//若出现过,记录编号if(D[j]==temp) {Target=j;break;}}if(!~Target){//若没出现过,用新的编号 Target=Dn++;D[Target]=temp;}D[i].next[k]=Target;//记录i往四个方向转动后的状态的编号 }}//显示Dices/* for(int i=0;i<Dn;i++){printf("%d:",i);D[i].show();for(int k=0;k<4;k++) printf("->%d",D[i].next[k]);cout<<endl;}*///计算  (SPFA)for(int i=0;i<1536;i++) game[i].init(i);memset(inq,0,sizeof(inq));Q.push(Sx*8+Sy);inq[Sx*8+Sy]=1;game[Sx*8+Sy].Dis=D[0].a[4];while(!Q.empty()){int cnt=Q.front();Q.pop();inq[cnt]=0;Bfs(cnt);}//搜索答案 int ANS=-1;int ANSI=-1;for(int i=0;i<Dn;i++){//搜索每一层if(~game[i*64+Dx*8+Dy].Dis){//如果可以到达if(!~ANS||game[i*64+Dx*8+Dy].Dis<ANS){//ANS未找到,或者新距离小于原始ANS  则更新。ANS=game[i*64+Dx*8+Dy].Dis;ANSI=i*64+Dx*8+Dy;}}}//输出答案 cout<<ANS;F(ANSI);cout<<endl;return 0;}




0 0
原创粉丝点击