首页 > 代码库 > 【线性规划与网络流24题】孤岛营救问题 分层图

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

孤岛营救问题

Time Limit: 1 Sec  Memory Limit: 128 MB

Description

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

大兵瑞恩被关押在迷宫的东南角,即(N,M)单元里,并已经昏迷。迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入(1,1)单元。另外,麦克从一个单元移动到另一个相邻单元的时间为 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。 

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。 

Input

第 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类门的。(其中 1<=Qi<=P)。
输入数据中同一行各相邻整数之间用一个空格分隔。 

 

Output

输出麦克营救到大兵瑞恩的最短时间的值。如果问题无解,则输出-1。

Sample Input

4 4 991 2 1 3 21 2 2 2 02 1 2 2 02 1 3 1 02 3 3 3 02 4 3 4 13 2 3 3 03 3 4 3 04 3 4 4 022 1 24 2 1

Sample Output

14

HINT

N,M,P <= 10

K < 150

Source

网络流24题


    题意不多说了,自己读题就好了。然后要注意的是每个点可能有多个钥匙,两个房间之间不可能需要连穿两扇门。还有就是判断两个房间能不能通过的时候不必枚举二进制下每位是0还是1,直接假设门需要的钥匙为y,而当前代表钥匙01串的数是x,那么可以把门的钥匙设为(1<<y),则if(x%((1<<y)*2) >=(1<<y))就可以了,试想,把前面的钥匙去掉,然后剩下的钥匙若能开,hash值一定>=门号,否则你懂得,不多说了,不懂?手模拟!。

    建边时候注意点,转移时注意点,很快就能水过。

不会分层图的同学看这个:http://blog.csdn.net/vmurder/article/details/40075989

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200
#define P 3000
#define inf 0x3f3f3f3f
using namespace std;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
int n,m,p,f;
int map[N][N],id[N][N],key[N];
struct KSD
{
	int v,len,next;
}e[N*N*4];
int head[N],cnt;
void add(int u,int v,int len)
{
	++cnt;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
struct Lux
{
	int x,y;
	Lux(int a,int b):x(a),y(b){}
	Lux(){}
};
int s,t,dist[P][N];
bool in[P][N];
int spfa()
{
	int i,u,v,temp;
	memset(dist,0x3f,sizeof(dist));
	dist[1][s]=0;
	in[1][s]=1;
	queue<Lux>q;
	q.push(Lux(1,s));
	while(!q.empty())
	{
		Lux U=q.front();q.pop();
		u=U.y;
		in[U.x][u]=0;
		dist[U.x|key[U.y]][U.y]=min(dist[U.x|key[U.y]][U.y],dist[U.x][U.y]);
		U.x|=key[U.y];
		
		for(i=head[u];i;i=e[i].next)if(U.x%(e[i].len<<1)>=e[i].len)
		{
			v=e[i].v;
			if(dist[U.x][v]>dist[U.x][U.y]+1)
			{
				dist[U.x][v]=dist[U.x][U.y]+1;
				if(!in[U.x][v])
				{
					in[U.x][v]=1;
					q.push(Lux(U.x,v));
				}
			}
		}
	}
	int ret=inf;
	for(i=1;i<P;i++)ret=min(ret,dist[i][t]);
	if(ret==inf)ret=-1;
	return ret;
}

int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	scanf("%d%d%d%d",&n,&m,&p,&f);
	for(s=i=1;i<=n;i++)for(j=1;j<=m;j++)id[i][j]=++t;
	memset(map,-1,sizeof(map));
	for(i=1;i<=f;i++)
	{
		scanf("%d%d",&a,&b);a=id[a][b];
		scanf("%d%d",&b,&c);b=id[b][c];
		scanf("%d",&c);map[a][b]=map[b][a]=c;
		if(c)add(a,b,1<<c),add(b,a,1<<c);
	}
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)
	{
		a=id[i][j];
		for(k=0;k<4;k++)
		{
			int x=i+dx[k];
			int y=j+dy[k];
			b=id[x][y];
			if(map[a][b]==-1&&b)add(a,b,1);
		}
	}
	scanf("%d",&f);
	for(i=1;i<=f;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		key[id[a][b]]|=1<<c;
	}
	printf("%d\n",spfa());
	return 0;
}

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