网络流24题-孤岛营救问题
时空限制1000ms / 256MB
题目描述
1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 N 行,东西方向被划分为 M 列,于是整个迷宫被划分为 N×M 个单元。每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示。南北或东西方向相邻的 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成P 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。
大兵瑞恩被关押在迷宫的东南角,即 (N,M) 单元里,并已经昏迷。迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 (1,1) 单元。另外,麦克从一个单元移动到另一个相邻单元的时间为 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。
试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。
输入输出格式
输入格式:第 1 行有 3 个整数,分别表示 N,M,P 的值。
第 2 行是 1 个整数 K,表示迷宫中门和墙的总数。
第 I+2 行(1≤I≤K),有 5 个整数,依次为Xi1,Yi1,Xi2,Yi2,Gi:
-
当Gi≥1 时,表示 (Xi1,Yi1) 单元与(Xi2,Yi2) 单元之间有一扇第 Gi 类的门
-
当Gi=0 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一堵不可逾越的墙(其中,∣Xi1−Xi2∣+∣Yi1−Yi2∣=1,0≤Gi≤P)。
第 K+3 行是一个整数 S,表示迷宫中存放的钥匙总数。
第 K+3+J 行(1≤J≤S),有 3 个整数,依次为Xi1,Yi1,Qi:表示第 J 把钥匙存放在 (Xi1,Yi1)单元里,并且第 J 把钥匙是用来开启第 Qi 类门的。(其中 P1≤Qi≤P)。
输入数据中同一行各相邻整数之间用一个空格分隔。
输出格式:将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出 −1。
输入输出样例
说明
∣Xi1−Xi2∣+∣Yi1−Yi2∣=1,0≤Gi≤P
1≤Qi≤P
N,M,P≤10,K<150,S≤14
题目链接:https://www.luogu.org/problemnew/show/P4011
状态压缩+BFS。最近感觉做了不少这样的bfs题,大思路就是对每种状态都记录一下最优答案,以能否更新当前状态作为bfs的条件。
#include<bits/stdc++.h> #define N 105 using namespace std; struct ss { int v,next,type; }; ss edg[N*10]; int head[N],now_edge=0; void addedge(int u,int v,int type) { edg[now_edge]=(ss){v,head[u],type}; head[u]=now_edge++; edg[now_edge]=(ss){u,head[v],type}; head[v]=now_edge++; } vector<int>key[N]; int ans=INT_MAX; int dp[N][1<<10]; struct orz { int x,mykey,time; }; int n,m; void bfs() { queue<orz>q; memset(dp,0x3f3f3f3f,sizeof(dp)); int now_key=0; for(int j=0;j<key[1].size();j++) if(!(now_key&(1<<(key[1][j]-1))))now_key+=(1<<(key[1][j]-1)); q.push((orz){1,now_key,0}); while(!q.empty()) { orz now=q.front(); q.pop(); if(now.x==n*m) { ans=min(ans,now.time); continue; } for(int i=head[now.x];i!=-1;i=edg[i].next) { ss e=edg[i]; if(e.type==-1)continue; if(e.type==0||(e.type>0&&(now.mykey&(1<<(e.type-1))))) { if(dp[e.v][now.mykey]>now.time+1) { dp[e.v][now.mykey]=now.time+1; if(key[e.v].size()) { int now_key=now.mykey; for(int j=0;j<key[e.v].size();j++) if(!(now_key&(1<<(key[e.v][j]-1))))now_key+=(1<<(key[e.v][j]-1)); q.push((orz){e.v,now_key,now.time+1}); } else q.push((orz){e.v,now.mykey,now.time+1}); } } } } } int Map[N][N]={0}; int main() { int p; memset(head,-1,sizeof(head)); scanf("%d %d %d",&n,&m,&p); int k; scanf("%d",&k); while(k--) { int a,b,c,d,e; scanf("%d %d %d %d %d",&a,&b,&c,&d,&e); if(!e)e=-1; Map[(a-1)*m+b][(c-1)*m+d]=Map[(c-1)*m+d][(a-1)*m+b]=e; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(i+1<=n)addedge((i-1)*m+j,((i+1)-1)*m+j,Map[(i-1)*m+j][((i+1)-1)*m+j]); if(j+1<=m)addedge((i-1)*m+j,(i-1)*m+j+1,Map[(i-1)*m+j][(i-1)*m+j+1]); } scanf("%d",&k); while(k--) { int a,b,c; scanf("%d %d %d",&a,&b,&c); key[(a-1)*m+b].push_back(c); } bfs(); printf("%d\n",ans==INT_MAX ? -1 : ans); return 0; }