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

题目传送门

题目大意: 给出一张网格图,两个格子之间可能没东西,可以直接通过,或者有门,需要钥匙,又或者是墙,不可通过。一些格子上有钥匙,钥匙和门一共有 p p p 种,相同种类的才可以使用,问从 ( 1 , 1 ) (1,1) (1,1) 走到 ( n , m ) (n,m) (n,m) 最短需要多少时间。

题解

众所周知,网络流24题里出一些广搜是很正常的。

由于 p p p 很小,所以状压bfs即可。状压的是当前捡到的钥匙种类。

以及,虽然两个格子时间不会有多扇门,但是一个格子上可能有多个钥匙。

代码如下:

#include 
#include 
#include 
#include 
using namespace std;

int n,m,p,k,s;
vector<int> vec[11][11];
int a[11][11][11][11];
struct node{int x,y,key;}q[1000010];
int st=1,ed=2,f[11][11][1<<11];
int f1[4]={0,-1,0,1};
int f2[4]={-1,0,1,0};
int get(int x,int y,int xx,int yy)
{
	if((x-1)*m+y>(xx-1)*m+yy)swap(x,xx),swap(y,yy);
	return a[x][y][xx][yy];
}

int main()
{
	scanf("%d %d %d %d",&n,&m,&p,&k);
	for(int i=1,x,y,xx,yy,z;i<=k;i++)
	{
		scanf("%d %d %d %d %d",&x,&y,&xx,&yy,&z);
		if((x-1)*m+y>(xx-1)*m+yy)swap(x,xx),swap(y,yy);
		a[x][y][xx][yy]=(z?z:-1);
	}
	scanf("%d",&s);
	for(int i=1,x,y,z;i<=s;i++)
	scanf("%d %d %d",&x,&y,&z),vec[x][y].push_back(z);
	q[st]=(node){1,1,0};
	for(int i=0;i<vec[1][1].size();i++)q[st].key|=(1<<(vec[1][1][i]-1));
	memset(f,63,sizeof(f)); f[1][1][q[st].key]=0;
	while(st!=ed)
	{
		int x=q[st].x,y=q[st].y,key=q[st].key;
		st++;st=st>1000000?1:st;
		for(int i=0;i<4;i++)
		{
			int xx=x+f1[i],yy=y+f2[i];
			if(xx<1||xx>n||yy<1||yy>m)continue;
			int type=get(x,y,xx,yy);
			if(type==-1)continue;
			if(type==0||key&(1<<(type-1)))
			{
				int new_key=key;
				for(int j=0;j<vec[xx][yy].size();j++)
				new_key|=(1<<(vec[xx][yy][j]-1));
				if(f[xx][yy][new_key]>10000000)
				f[xx][yy][new_key]=f[x][y][key]+1,q[ed++]=(node){xx,yy,new_key};
			}
		}
	}
	int ans=999999999;
	for(int i=0;i<(1<<p);i++)ans=min(ans,f[n][m][i]);
	printf("%d",ans>1000000?-1:ans);
}

你可能感兴趣的:(网络流24题)