NOIP 2013 华容道
题目描述
【问题描述】
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
-
在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
-
有些棋子是固定的,有些棋子则是可以移动的;
- 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。
游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的, 但是棋盘上空白的格子的初始位置、 指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次
玩的时候, 空白的格子在第 EXi 行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi列,目标位置为第 TXi 行第 TYi 列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
输入输出格式
输入格式:输入文件为 puzzle.in。
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出格式:输出文件名为 puzzle.out。
输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。
输入输出样例
3 4 2 0 1 1 1 0 1 1 0 0 1 0 0 3 2 1 2 2 2 1 2 2 2 3 2
2 -1
说明
【输入输出样例说明】
棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。
- 第一次游戏,空白格子的初始位置是 (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。
题解:花搜(花式搜索)
f[i][j][l][k]表示空格从l方向移到k方向的步数
这里用bfs实现,注意这里要+1,因为后面SPFA移动时没有+1
还要注意bfs时不能经过(i,j),因为这样会使(i,j)移动
为什么不能使(i,j)移动?首先说明f数组是帮助SPFA时从(i,j,l)转移到(i,j,k)再转移到(x,y,kk)
显然在这个过程中(i,j)不能动,否则关键点就变了
这里kk是k的反方向
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 struct Node 8 { 9 int x,y,s; 10 }; 11 struct Space 12 { 13 int x,y,k; 14 }; 15 const int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 16 bool vis[31][31][5],v[31][31]; 17 int map[101][101],ans; 18 int f[31][31][5][5],dist[31][31][5]; 19 int n,m,sx,sy,tx,ty,ex,ey; 20 int bfs(Node S,Node T) 21 {int i; 22 queue<Node>Q; 23 Q.push(S); 24 memset(v,0,sizeof(v)); 25 if (S.x==T.x&&S.y==T.y) return 0; 26 v[S.x][S.y]=1; 27 while (Q.empty()==0) 28 { 29 Node u=Q.front(); 30 Q.pop(); 31 for (i=1;i<=4;i++) 32 { 33 int x=u.x+dx[i]; 34 int y=u.y+dy[i]; 35 if (x&&y&&x<=n&&y<=m&&map[x][y]) 36 { 37 if (x==T.x&&y==T.y) 38 { 39 // cout<<u.s+1<<endl; 40 return u.s+1; 41 } 42 if (v[x][y]==0) 43 { 44 Q.push((Node){x,y,u.s+1}); 45 v[x][y]=1; 46 } 47 } 48 } 49 } 50 return 1e9; 51 } 52 Node To(Node u,int k) 53 { 54 if (k==1) 55 return (Node){u.x-1,u.y,0}; 56 if (k==2) 57 return (Node){u.x+1,u.y,0}; 58 if (k==3) 59 return (Node){u.x,u.y-1,0}; 60 if (k==4) 61 return (Node){u.x,u.y+1,0}; 62 } 63 void prework() 64 {int i,j,k,l; 65 for (i=1;i<=n;i++) 66 { 67 for (j=1;j<=m;j++) 68 { 69 if (map[i][j]==0) continue; 70 map[i][j]=0; 71 for (l=1;l<=4;l++) 72 { 73 for (k=1;k<=4;k++) 74 { 75 if (l==k) 76 { 77 f[i][j][l][k]=f[i][j][k][l]=1; 78 continue; 79 } 80 if (l>k) 81 { 82 f[i][j][l][k]=f[i][j][k][l]; 83 continue; 84 } 85 Node t1=To((Node){i,j,0},l); 86 Node t2=To((Node){i,j,0},k); 87 if (map[t1.x][t1.y]==0||map[t2.x][t2.y]==0) continue; 88 f[i][j][l][k]=bfs(t1,t2)+1; 89 // printf("%d %d %d %d %d\n",i,j,l,k,f[i][j][l][k]); 90 } 91 } 92 map[i][j]=1; 93 } 94 } 95 } 96 int other(int x) 97 { 98 if (x==1) return 2; 99 if (x==2) return 1; 100 if (x==3) return 4; 101 if (x==4) return 3; 102 } 103 void SPFA() 104 {int i; 105 queue<Space>Q; 106 map[sx][sy]=0; 107 memset(dist,127/3,sizeof(dist)); 108 memset(vis,0,sizeof(vis)); 109 for (i=1;i<=4;i++) 110 { 111 int x=sx+dx[i]; 112 int y=sy+dy[i]; 113 if (map[x][y]==0) continue; 114 dist[sx][sy][i]=bfs((Node){ex,ey,0},(Node){x,y,0}); 115 Q.push((Space){sx,sy,i}); 116 vis[sx][sy][i]=1; 117 } 118 map[sx][sy]=1; 119 while (!Q.empty()) 120 { 121 Space u=Q.front(); 122 Q.pop(); 123 vis[u.x][u.y][u.k]=0; 124 for (i=1;i<=4;i++) 125 { 126 Node v=To((Node){u.x,u.y,0},i); 127 int kk=other(i); 128 if (map[v.x][v.y]==0) continue; 129 if (dist[v.x][v.y][kk]>dist[u.x][u.y][u.k]+f[u.x][u.y][u.k][i]) 130 { 131 dist[v.x][v.y][kk]=dist[u.x][u.y][u.k]+f[u.x][u.y][u.k][i]; 132 if (vis[v.x][v.y][kk]==0) 133 { 134 Q.push((Space){v.x,v.y,kk}); 135 vis[v.x][v.y][kk]=1; 136 } 137 } 138 } 139 } 140 ans=1e7; 141 for (i=1;i<=4;i++) 142 ans=min(ans,dist[tx][ty][i]); 143 } 144 int main() 145 {int T,i,j; 146 cin>>n>>m>>T; 147 for (i=1;i<=n;i++) 148 { 149 for (j=1;j<=m;j++) 150 { 151 scanf("%d",&map[i][j]); 152 } 153 } 154 prework(); 155 while (T--) 156 { 157 scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); 158 if (sx==tx&&sy==ty) 159 { 160 printf("0\n"); 161 continue; 162 } 163 SPFA(); 164 if (ans<1e7) 165 printf("%d\n",ans); 166 else printf("-1\n"); 167 } 168 }