洛谷 P4011 孤岛营救问题
链接:
题目描述:
\(1944\) 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 \(N\) 行,东西方向被划分为 \(M\) 列,于是整个迷宫被划分为 \(N\times M\) 个单元。每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示。南北或东西方向相邻的 \(2\) 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成 \(P\) 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。
输入格式:
第 \(1\) 行有 \(3\) 个整数,分别表示 \(N,M,P\) 的值。
第 \(2\) 行是 \(1\) 个整数 \(K\),表示迷宫中门和墙的总数。
第$ I+2$ 行\((1\leq I\leq K)\),有 \(5\) 个整数,依次为\(X_{i1},Y_{i1},X_{i2},Y_{i2},G_i\)(其中,\(|X_{i1}-X_{i2}|+|Y_{i1}-Y_{i2}|=1,0\leq G_i\leq P\)):
- 当 \(G_i \geq 1\) 时,表示 \((X_{i1},Y_{i1})\) 单元与 \((X_{i2},Y_{i2})\) 单元之间有一扇第 \(G_i\) 类的门
- 当 \(G_i=0\) 时,表示 \((X_{i1},Y_{i1})\) 单元与 \((X_{i2},Y_{i2})\) 单元之间有一堵不可逾越的墙。
第 \(K+3\) 行是一个整数 \(S\),表示迷宫中存放的钥匙总数。
第 \(K+3+J\) 行\((1\leq J\leq S)\),有 \(3\) 个整数,依次为 \(X_{i1},Y_{i1},Q_i\):表示第 J 把钥匙存放在 \((X_{i1},Y_{i1})\) 单元里,并且第$ J$ 把钥匙是用来开启第 \(Q_i\) 类门的。(其中\(1\leq Q_i\leq P\))。
输入数据中同一行各相邻整数之间用一个空格分隔。
分析:
网络流24题?网络流呢?我怎么又看到一个分层图水题。
一样用dijkstra,但是此时状态是这14把钥匙,所以需要状压一下。
另外把没有限制的边设成限制为 \(p+1\) ,状态初值赋成 1<<(p+1) 就能统一处理所有边了。
由于不确定是否会有多个钥匙在一个格子内,我写了个链表,结果和存图的链表写重了,后面再写要考虑换个变量名。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=105;
const int M=1005;
const int inf=0x7fffffff;
const int K=80005;//>2^{16}
struct edge{
int v,g,next;
}e[M];
int head[N],en;
void insert(int u,int v,int g){
e[++en].v=v;
e[en].g=g;
e[en].next=head[u];
head[u]=en;
}
int n,m,p,k,S,s,t;
inline int pos(int i,int j){return (i-1)*m+j;}
int ax[4]={0,1,0,-1};
int ay[4]={1,0,-1,0};
int mp[N][N];
inline void addedge(int i,int j){
int u=pos(i,j);
for(int x=0;x<4;x++){
int tx=i+ax[x],ty=j+ay[x],v=pos(tx,ty);
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&!mp[u][v]){
insert(u,v,p+1);
insert(v,u,p+1);
}
}
}
struct kk{
int g,next;
}key[15];
int headk[N],kn;
inline void insertk(int u,int g){
key[++kn].g=g;
key[kn].next=headk[u];
headk[u]=kn;
}
struct node{
int dis,u,key;
};
bool operator<(const node &a,const node &b){
return a.dis<b.dis;
}
int vis[N][K];
priority_queue<node>q;
int dijkstra(){
memset(vis,0,sizeof(vis));
node temp;
temp.dis=0;
temp.u=s;
temp.key=1<<(p+1);
q.push(temp);
while(!q.empty()){
int u=q.top().u,dis=-q.top().dis,ky=q.top().key;q.pop();
for(int i=headk[u];i;i=key[i].next)
ky|=(1<<key[i].g);
if(u==t)return dis;
if(vis[u][ky])continue;
vis[u][ky]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v,g=e[i].g;
if((ky>>g)&1){
temp.dis=-dis-1;
temp.u=v;
temp.key=ky;
q.push(temp);
}
}
}
return -1;
}
signed main(){
n=in,m=in,p=in,k=in,s=1,t=n*m;
for(int i=1;i<=k;i++){
int x=in,y=in,a=in,b=in,g=in;
int tx=pos(x,y),ty=pos(a,b);
insert(tx,ty,g);
insert(ty,tx,g);
mp[tx][ty]=mp[ty][tx]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
addedge(i,j);
S=in;
for(int i=1;i<=S;i++){
int x=in,y=in,g=in;
insertk(pos(x,y),g);
}
cout<<dijkstra();
return 0;
}
按理说dijkstra应该比bfs快啊,为什么我跑不过

浙公网安备 33010602011771号