【codevs 1911 孤岛营救问题】

·为了分析方便,可以先做一个题目简化。去掉“钥匙”这个条件,那么就是一个BFS或者SPFA……现在加上该条件。如本题只给出最多两种钥匙,当然你可以继续坚持BFS等方式,时间不会太差。但是一旦钥匙种类上升至15的时候,就有太多情况需要处理(光说你写BFS的if就是很长的过程,但个人认为时间复杂度依旧能过这道题)。

·如图是简化版本的决策方式(为与后文呼应,用SPFA):

大方块是整个地图。小方块是一个房间。那么你可以在向四个方向走,前提是有路可走(没有墙)。你本可以轻松拯救大兵瑞恩,然后过上幸福快乐的生活,但是你可能在实际问题中遭遇这样的绝望情况:

       明明有路可走,但是那扇门你没有钥匙。现在你开始幻想,怎样才能走过去呢……你妄想:要是在这之前有开这扇门的钥匙就好了,那我同样是走相同的路来到这扇门前,但是在那个时空的我就可以轻松开门,这个时空的我就只能绝望地去他地寻找钥匙。

·我们谈到了时空断裂。那么就干脆把每个时空也作为状态的一部分吧!(注意,在这之前你的状态只有一个元素,就是当前点坐标)。

·由图可见,你要时空穿梭的条件是你必须具备相应的钥匙。图中:如果你在这个房间里捡到了B,C钥匙,那么就有这种穿越方式(蓝色有向边)。由于在这里“时空”与“坐标位置”的地位是相同的【它们无制约关系】。也就是说你穿越两次时空在向左走一步,和将这些动作反过来,在可行的情况下是等价的。说明这一点的目的在于:这启示我们,其实这图中6条边的意义是相同的。

         这样一来,这道题就变成了普通的最短路问题,只是路多了些,判断条件多了些。所以可以用二维状态来表示当前情况,最终答案在每个时空里找一个最优的即可(没喊你把所有钥匙拿完啊!)。

 1 #include<bits/stdc++.h>
 2 #define go(i,a,b) for(int i=a;i<=b;i++)
 3 #define fo(i,a,x) for(int i=a[x];i>-1;i=e[i].next)
 4 #define mem(a,b) memset(a,b,sizeof(a))
 5 #define P 3000
 6 #define inf 0x3f3f3f3f
 7 using namespace std;const int N=203;
 8 int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
 9 int n,m,p,f,S[N][N],id[N][N],key[N],head[N],k=0,s,t,dis[P][N];
10 struct E{int v,next,rar;}e[N*N*4];bool inq[P][N];
11 void ADD(int u,int v,int rar){e[k]=(E){v,head[u],rar};head[u]=k++;}
12 struct G{int x,y;};
13 int spfa()
14 {
15     mem(dis,0x3f);dis[1][1]=0;inq[1][1]=1;
16     queue<G>q;q.push((G){1,1});
17     while(!q.empty())
18     {
19         G U=q.front();q.pop();inq[U.x][U.y]=0;
20         dis[U.x|key[U.y]][U.y]=min(dis[U.x|key[U.y]][U.y],dis[U.x][U.y]);
21         U.x|=key[U.y];
22
23         fo(i,head,U.y)if(U.x%(e[i].rar<<1)>=e[i].rar)
24         {
25             int v=e[i].v;
26             if(dis[U.x][v]>dis[U.x][U.y]+1)
27             {
28                 dis[U.x][v]=dis[U.x][U.y]+1;
29                 if(!inq[U.x][v])
30                 {
31                     inq[U.x][v]=1;
32                     q.push((G){U.x,v});
33                 }
34             }
35         }
36     }
37     int ret=inf;go(i,1,P-1)ret=min(ret,dis[i][t]);
38     if(ret==inf)ret=-1;return ret;
39 }
40
41 int main()
42 {
43
44     int k,a,b,c;mem(S,-1);mem(head,-1);
45     scanf("%d%d%d%d",&n,&m,&p,&f);
46     go(i,1,n)go(j,1,m)id[i][j]=++t;
47     go(i,1,f){scanf("%d%d",&a,&b);a=id[a][b];
48         scanf("%d%d",&b,&c);b=id[b][c];
49         scanf("%d",&c);S[a][b]=S[b][a]=c;
50         if(c)ADD(a,b,1<<c),ADD(b,a,1<<c);}
51
52     go(i,1,n)go(j,1,m)
53     {
54         a=id[i][j];go(k,0,3)
55         {
56             int x=i+dx[k],y=j+dy[k];b=id[x][y];
57             if(S[a][b]==-1&&b)ADD(a,b,1);
58         }
59     }
60     scanf("%d",&f);
61     go(i,1,f)scanf("%d%d%d",&a,&b,&c),key[id[a][b]]|=(1<<c);
62     printf("%d\n",spfa());
63     return 0;
64 }

【大米饼代码】

·最后来一句关于代码疑难的提示:

到达同一个地点时,手上的钥匙越多越好,不要害怕。

比起那些政客的谎言,我们要圣洁得多。

时间: 2024-12-17 16:28:52

【codevs 1911 孤岛营救问题】的相关文章

【网络流24题----14】孤岛营救问题

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令.要求马上赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能互

【线性规划与网络流24题】孤岛营救问题 分层图

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每一个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能

孤岛营救问题

孤岛营救问题 题目链接 题目描述 \(1944\)年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为\(N\)行,东西方向被划分为\(M\)列,于是整个迷宫被划分为\(N\times M\)个单元.每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示.南北或东西方向相邻的 \(22\)个单元之间可能互通,也可能有一扇锁着的门,或者是一堵

【网络流24题】 No.14 孤岛营救问题 (分层图最短路)

[题意] 1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛, 营救被敌军俘虏的大兵瑞恩. 瑞恩被关押在一个迷宫里, 迷宫地形复杂, 但幸好麦克得到了迷宫的地形图. 迷宫的外形是一个长方形, 其南北方向被划分为 N 行,东西方向被划分为 M 列,于是整个迷宫被划分为 N× M 个单元.每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示.南北或东西方向相邻的 2 个单元之间可能互通, 也可能有一扇锁着的门,或者是一堵不可逾越的墙.迷宫中有一些单元存放着钥匙, 并

【CTSC1999】拯救大兵瑞恩(孤岛营救问题)

2219 拯救大兵瑞恩 1999年CTSC国家队选拔赛 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但是幸好麦克得到了迷宫的地形图. 迷宫的外形是一个长方形,其在南北方向被划分为N行,在东西方向被划分为M列,于是整个迷宫被划分为N*M个单元.我们用一个有序数对(单元的行号,单元的列号)来表

网络流24题 之十四 孤岛营救问题 分层图

题目大意:一张网格图,上面有一些点可能有某种钥匙.节点和节点之间可能有门.有些门须要特定的钥匙就能够通过,有些不管怎样都过不去.求从(1,1)開始到(m,n)的最短时间. 思路:分层图+状态压缩. f[i][j][k],当中i和j描写叙述的是当前所在的位置.k是压缩了的当前有哪些钥匙(因为钥匙的数量<=10,所以全部的状态1<<10的空间内就能够搞定).然后向四个方向更新的时候推断能否经过门. CODE: #include <queue> #include <cstdi

洛谷 [P4011] 孤岛营救问题

状压+BFS 通过观察数据范围可知,我们应该状压钥匙种类,直接BFS即可 注意,一个点处可能不知有一把钥匙 #include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> #include <queue> using namespace std; bool f[14][14][1200]; int n,m,p,k,s,key[15][15],block1[

洛谷 P4011 孤岛营救问题【bfs】

注意: 一个点可能有多把钥匙,所以把每个点有钥匙的情况状压一下 两个点之间有障碍的情况只给出了单向,存的时候记得存一下反向 b[i][j]表示当前点拥有钥匙的状态,g[x1][y1][x2][y2]表示两点之间门的类型(0表示没有,-1表示墙比较方便),f[i][j][k]表示点(i,j)在拥有k状态钥匙的情况下的最小步数,v[i][j][k]表示f[i][j][k]的状态是否在bfs队列里.然后转移比较类似spfa 以及终于知道为什么这种题会在24题里了-因为24全名"网络流与线性规划二十四题

[题解]luogu_P4011_孤岛营救问题(状压bfs/最短路

钥匙只有10种可以状压,最短路或者bfs都行,但是写挂了(现在还是 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define pb push_back using namespace std; const int maxn=13; const int dx[]={-1,0,1,0}; const int dy[]={0,1,0,-1}; int n,m,p,k,