标签:
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
有些棋子是固定的,有些棋子则是可以移动的;
任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EXiEXi
行第 EYiEYi
列,指定的可移动棋子的初始位置为第 SXiSXi
行第 SYiSYi
列,目标位置为第 TXiTXi
行第 TYiTYi
列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EXiEXi
、EYiEYi
、SXiSXi
、SYiSYi
、TXiTXi
、TYiTYi
,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。
每个测试点1s。
棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。
第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。
移动过程如下:
第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。
要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。
对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;
对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;
对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。
看到这道题,又有一点小兴奋,因为是华容道这个游戏(好吧,好像是游戏我都很激动-.-),但是由于对BFS的不熟悉,(也就是“公式”还没有背到),知道要写BFS的我也无能为力。。。。所以顺带复习了一下BFS和增量数组。
增量数组:zl[2][4]={{0,0,1,-1},{1,-1,0,0}};
bfs:
1 int bfs() 2 { 3 //初始化,初始状态存入队列 //或queue<int>q; 4 //队首指针 head=0;尾指针 tail=1; // q.push(1) 5 do //while (!q.empty()) 6 { 7 //指针head++; 指向待扩展结点 //int now=q.front(),q.pop() 8 for (int i=1;i<=max;i++) 9 { 10 if (/*子节点符合条件*/) 11 { 12 tail ++;//新节点存入队尾 //q.push(i) 13 if(/*新节点与原结点重复*/) 14 //删去该节点(取消入队,tail--) 15 else 16 if(/*新节点是目标结点*/) //输出并退出 17 18 } 19 } 20 } while (head<tail); 21 }
啊,最后这道题还是只写了一个70分的代码,弃坑。(不不不,以后有时间还是要写的)
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<string> 6 using namespace std; 7 int n,m,q; 8 int chess[35][35]; 9 const int zl[2][4]={{0,1,-1,0},{1,0,0,-1}}; 10 bool b[35][35][35][35]; 11 struct pp{ 12 int ex,ey,sx,sy; 13 int step; 14 }; 15 pp node[810005]; 16 bool pd(int x1,int y1,int x2,int y2) 17 { 18 if (x2<1||x2>n||y2<1||y2>m||!chess[x2][y2]) return false; 19 if (b[x1][y1][x2][y2]) return false; 20 b[x1][y1][x2][y2]=true; 21 return true; 22 } 23 void bfs() 24 { 25 memset(b,false,sizeof(b)); 26 int tx,ty; 27 scanf("%d%d%d%d%d%d",&node[0].ex,&node[0].ey,&node[0].sx,&node[0].sy,&tx,&ty); 28 int head=0,tail=0; 29 if (tx==node[0].sx&&ty==node[0].sy) {cout<<0<<endl;return ;} 30 b[node[0].sx][node[0].sy][node[0].ex][node[0].ey]=true; 31 node[tail].step=0;//初始化 32 while(head<=tail) 33 { 34 for (int i=0;i<=3;i++) 35 { 36 int x=node[head].sx,y=node[head].sy; 37 int x1=node[head].ex+zl[0][i],y1=node[head].ey+zl[1][i]; 38 if (x==x1&&y==y1) {x=node[head].ex;y=node[head].ey;}/*!!!!*/ 39 if (pd(x,y,x1,y1)) 40 { 41 tail++; 42 node[tail].sx=x;node[tail].sy=y;//入队 43 node[tail].ex=x1;node[tail].ey=y1; 44 node[tail].step=node[head].step+1; 45 if (x==tx&&y==ty) {cout<<node[tail].step<<endl;return ;} 46 } 47 } 48 head++; 49 }while (head<tail); 50 cout<<-1<<endl; 51 return ; 52 } 53 int main() 54 { 55 freopen("puzzle.in","r",stdin); 56 freopen("puzzle.out","w",stdout); 57 cin>>n>>m>>q; 58 for(int i=1;i<=n;i++) 59 for(int j=1;j<=m;j++) 60 scanf("%d",&chess[i][j]); 61 for (int i=1;i<=q;i++) 62 bfs(); 63 return 0; 64 }
完整100代码是spfa 和 bfs:(复制版本)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <queue> 6 #define MaxN 35 7 using namespace std; 8 const int 9 INF=~0U>>2, 10 dx[]={0,0,-1,1}, 11 dy[]={-1,1,0,0};//注意顺序,才易实现0变1,1变0;2变3,3变2 12 int mat[MaxN][MaxN],dis[MaxN][MaxN][4]; 13 bool vis[MaxN][MaxN][4]; 14 int step[MaxN][MaxN][4][4]; 15 int d[MaxN][MaxN]; 16 int n,m,q,test,ex,ey,sx,sy,tx,ty; 17 struct node 18 { 19 int x,y; 20 }; 21 struct node2 22 { 23 int x,y,k; 24 }; 25 bool inside(int x, int y) 26 { 27 return (x>=1&&x<=n&&y>=1&&y<=m); 28 } 29 int spfa() 30 { 31 queue<node2> q; 32 memset(vis,false,sizeof(vis)); 33 while(!q.empty()) q.pop();//局部队列,可能非空,所以清空 34 for(int k=0;k<4;k++)//把初始位置棋子与空格相邻,四个方向组成的四种可能的步数入队,当成四个源点。 35 if(dis[sx][sy][k]!=INF) 36 { 37 q.push((node2){sx,sy,k}); 38 vis[sx][sy][k]=true; 39 } 40 while(!q.empty()) 41 { 42 int x=q.front().x; 43 int y=q.front().y; 44 int k=q.front().k; 45 q.pop(); 46 vis[x][y][k]=false; 47 for(int i=0;i<4;i++) 48 { 49 int _x=x+dx[i];//棋子(x,y)扩展的点(_x,_y) 50 int _y=y+dy[i]; 51 if(inside(_x,_y)) 52 if(mat[_x][_y]) 53 if(step[x][y][k][i]!=INF)//棋子(x,y)k方向空格可以移到棋子(x,y)i方向。 54 if(dis[_x][_y][i^1]>dis[x][y][k]+step[x][y][k][i]+1) 55 {//棋子(x,y)k方向空格移到棋子(x,y)i方向,再把棋子移到空格上,所以+1,空格变成i^1方向。 56 dis[_x][_y][i^1]=dis[x][y][k]+step[x][y][k][i]+1; 57 if (not vis[_x][_y][i^1]) 58 { 59 q.push((node2){_x,_y,i ^ 1 }); 60 vis[_x][_y][i^1]=true; 61 } 62 } 63 } 64 } 65 int ans=INF; 66 for(int i=0;i<4;i++) 67 if(dis[tx][ty][i]<ans) 68 ans=dis[tx][ty][i];//找出目标位置与空格相邻四种情况最少步数 69 return (ans==INF)? -1:ans; 70 } 71 int bfs(int sx,int sy,int tx,int ty)//将空格从(sx,sy)移到(tx,ty)的步数 72 { 73 if(!mat[sx][sy]) 74 return INF; 75 if(!mat[tx][ty]) 76 return INF; 77 for(int i=1;i<=n;i++) 78 for(int j=1;j<=m;j++) 79 d[i][j]=INF;//INF可以做为没有到过的标志 80 d[sx][sy]=0; 81 queue<node> q;//局部队列,可能非空,所以清空 82 while(!q.empty()) q.pop(); 83 q.push((node){sx,sy}); 84 while(!q.empty()) 85 { 86 if(d[tx][ty]!=INF) 87 return d[tx][ty]; 88 int x=q.front().x; 89 int y=q.front().y; 90 q.pop(); 91 for(int i=0;i<4;i++) 92 { 93 int _x=x+dx[i]; 94 int _y=y+dy[i]; 95 if(inside(_x,_y)) 96 if(mat[_x][_y]&&d[_x][_y]==INF) 97 { 98 d[_x][_y]=d[x][y]+1; 99 //if(d[tx][ty]!=INF) 100 // return d[tx][ty]; 101 //与下面不等价,有可能(sx,sy)与(tx,ty)一样,所以最好放在出队前判断 102 //if (_x==tx&&_y==ty) return d[tx][ty];???? 103 q.push((node){_x,_y}); 104 } 105 } 106 } 107 return INF; 108 } 109 void init() 110 { 111 for(int i=1;i<=n;i++) 112 for(int j=1;j<=m;j++) 113 { 114 int v=mat[i][j]; 115 mat[i][j]=0;//此位置可能是0或1,均改成0,因为移动空格不能移动棋子(i,j) 116 for (int k=0;k<4;k++) 117 for (int l=0;l<4;l++) 118 step[i][j][k][l]=bfs(i+dx[k],j+dy[k],i+dx[l],j+dy[l]); 119 //step[i][j][k][l] 棋子(i,j)k方向相邻的空格移动到相邻的l方向的步数, 120 mat[i][j]=v;//还原 121 } 122 } 123 int getAns() 124 { 125 scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); 126 if(sx==tx&&sy==ty)//初始位置与目标位置同,0步 127 return 0; 128 if(sx==ex&&sy==ey)//初始位置与空格位置同,无解 129 return -1; 130 if(!inside(ex,ey)||!inside(sx,sy)||!inside(tx,ty))//三个位置至少有一个在棋盘外 131 return -1; 132 if(!mat[ex][ey]||!mat[sx][sy]||!mat[tx][ty])////三个位置至少有一个是固定的 133 return -1; 134 for(int i=1;i<=n;i++) 135 for (int j=1;j<=m;j++) 136 for (int k=0;k<4;k++) 137 dis[i][j][k]=INF; 138 mat[sx][sy]=0;//此时一定是1,改成0,因为前面已经判断过 139 for(int k=0;k<4;k++) 140 dis[sx][sy][k]=bfs(ex,ey,sx+dx[k],sy+dy[k]); 141 //dis[sx][sy][k]表示将空格移到(sx,sy)相邻并在k方向上的步骤 142 mat[sx][sy]=1; //还原 143 return spfa(); 144 } 145 int main() 146 { 147 freopen("puzzle.in","r",stdin); 148 freopen("puzzle.out","w",stdout); 149 scanf("%d%d%d",&n,&m,&test); 150 for(int i=1;i<=n;i++) 151 for(int j=1;j<=m;j++) 152 scanf("%d",&mat[i][j]); 153 init(); 154 while(test--) 155 printf("%d\n",getAns()); 156 return 0; 157 }
啊,太长了,一定要好好消化。。。
标签:
原文地址:http://www.cnblogs.com/lx0319/p/5664964.html