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 }

 

posted @ 2021-04-29 19:11  acmloser  阅读(68)  评论(0编辑  收藏  举报