AcWing 1131. 拯救大兵瑞恩
考察:双端队列+BFS+拆点
错误思路:
一开始想的是普通的BFS,但是用st数组记录有了哪些钥匙,但本蒟蒻脑子短路将st数组定义成全局变量.实际上是每一个点定义一个数存储该点有哪些钥匙.然后存储边想的是mp[x][y][i]表示x,y的i方向需要第几把钥匙.题解有类似写法,这种写法就是普通的BFS.
思路二:
定义d[x][y]为到达[x][y]的最短时间,实际上如果求解只记录x,y是没用的,所以需要扩展一维,定义d[x][y][st]为到达(x,y)处,所拥有的钥匙为st的最短时间.起始点是d[1][1][0],终点是d[n][m][任意].
以dp的角度来思考的话.状态转移方程是
(1) d[dx][dy][st] = min(d[x][y][st]+1,d[dx][dy][st]) 此处没有钥匙
(2) d[x][y][st|key[x][y]] = min(d[x][y][st],d[x][y][st|key[x][y]) 有钥匙直接拿.
dp的求解过程是依赖上一状态递推得到,所以dp循环求解状态一定要是拓扑序.但是本题存在环,也就是(x,y) <--> (dx,dy)互相可达.所以转化为最短路求解.这里边权要么0,要么1.所以可以用双端队列,时间复杂度比最短路稳定.
区分BFS与其他最短路st数组区别:BFS的st数组是标记哪些点遍历了.
1 #include <iostream> 2 #include <cstring> 3 #include <set> 4 #include <deque> 5 using namespace std; 6 typedef pair<int,int> PII; 7 const int N = 11,M = (1<<10)+10,INF = 0x3f3f3f3f; 8 int idx,n,m,p,mp[N][N],h[N*N],key[N*N],dist[N*N][M]; 9 bool g[N*N][N*N],st[N*N][M]; 10 int xx[4] = {-1,1,0,0},yy[4] = {0,0,-1,1}; 11 struct Road{ 12 int to,ne,w; 13 }road[N*N*4]; 14 void add(int a,int b,int c) 15 { 16 road[idx].w = c,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 17 } 18 void init() 19 { 20 for(int i=1;i<=n;i++) 21 for(int j=1;j<=m;j++) 22 for(int k=0;k<4;k++) 23 { 24 int dx = i+xx[k],dy = j+yy[k]; 25 if(dx>=1&&dx<=n&&dy>=1&&dy<=m) 26 { 27 int a = mp[i][j],b = mp[dx][dy]; 28 if(g[a][b]||g[b][a]) continue; 29 add(a,b,0); add(b,a,0);//将边权0定义为不需要钥匙 30 g[a][b] = g[b][a] =1; 31 } 32 } 33 } 34 int bfs() 35 { 36 deque<PII> q; 37 memset(dist,0x3f,sizeof dist); 38 dist[mp[1][1]][0] = 0;//拆点,0表示什么钥匙都没有 39 q.push_back({mp[1][1],0}); 40 while(q.size()) 41 { 42 PII it = q.front(); 43 q.pop_front(); 44 int u = it.first,state = it.second; 45 if(u==mp[n][m]) return dist[u][state]; 46 if(st[u][state]) continue; 47 st[u][state] = 1; 48 if(key[u]) 49 { 50 int nst = state|key[u]; 51 if(dist[u][nst]>dist[u][state]) 52 { 53 dist[u][nst] = dist[u][state]; 54 q.push_front({u,nst}); 55 } 56 } 57 for(int i=h[u];~i;i=road[i].ne) 58 { 59 int v = road[i].to; 60 bool ok = 0; 61 if(road[i].w&&!(state>>road[i].w-1&1)) continue; 62 if(dist[v][state]>dist[u][state]+1) 63 { 64 dist[v][state] = dist[u][state] +1; 65 q.push_back({v,state}); 66 } 67 } 68 } 69 return -1; 70 } 71 int main() 72 { 73 scanf("%d%d%d",&n,&m,&p); 74 int t = 0; 75 memset(h,-1,sizeof h); 76 for(int i=1;i<=n;i++) 77 for(int j=1;j<=m;j++) 78 mp[i][j] = ++t; 79 int k; 80 scanf("%d",&k); 81 while(k--) 82 { 83 int x1,y1,x2,y2,c; 84 scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c); 85 int a = mp[x1][y1],b = mp[x2][y2]; 86 if(c) add(a,b,c),add(b,a,c); 87 g[a][b] = g[b][a] = 1; 88 } 89 scanf("%d",&k); 90 for(int i=1;i<=k;++i) 91 { 92 int x,y,c; scanf("%d%d%d",&x,&y,&c); 93 key[mp[x][y]] |= 1<<c-1; 94 } 95 init(); 96 printf("%d\n",bfs()); 97 return 0; 98 }