洛谷 P4011 孤岛营救问题

链接:

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快啊,为什么我跑不过

posted @ 2021-08-05 16:44  llmmkk  阅读(50)  评论(0)    收藏  举报