Jzoj P5459 密室___状压spfa

题目大意:

N N N个房间,小 X X X开始在房间 1 1 1,出口在房间 N N N,有 K K K种类型的钥匙,给出通过某个房间能获得的钥匙,有 M M M个传送门,每个传送门单向的从房间 X X X通向房间 Y Y Y,而使用需要通过一些钥匙的搭配才能开启,钥匙在使用并不会消失。
问最少通过多少个传送门才能到达出口。
如果不能逃出这个密室,输出 N o S o l u t i o n No Solution NoSolution

N ≤ 5000 , M ≤ 6000 , K ≤ 10 N≤5000,M≤6000,K≤10 N5000,M6000,K10

分析:

我们发现 K K K并不大,于是可以把钥匙的获取情况压缩成一个二进制的状态,用十进制表示。
d i s [ i ] [ j ] dis[i][j] dis[i][j]表示表示从点 1 1 1到点 i i i获得了的钥匙状态为 j j j时通过的最少传送门。
然后就是一个简单的 s p f a spfa spfa了,判断传送门能否合法通过的时候,利用一些位运算的操作即可。

代码:

#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f
#define N 5005
#define M 6005

using namespace std;

struct Node { int To, nxt, num;}e[M];
int dis[N][1<<10], vis[N][1<<10], ls[N], a[N], n, m, k;

queue  Q1;
queue  Q2;

void spfa()
{ 
    for (int i = 1; i <= n; i++)
	     for (int j = 0; j <= ((1 << k) - 1); j++) dis[i][j] = inf;
    dis[1][a[1]] = 0;	
    Q1.push(1);
    Q2.push(a[1]);
    vis[1][a[1]] = 1;
	while (Q1.size())
	{
	       int u = Q1.front(); Q1.pop();
	       int cp = Q2.front(); Q2.pop();
		   for (int i = ls[u]; i; i = e[i].nxt)
		   {
		   	    int v = e[i].To;
		        if ((cp & e[i].num) == e[i].num)
		        {
					int rp = cp | a[e[i].To];
		            if (dis[v][rp] > dis[u][cp] + 1)
					{
		             	dis[v][rp] = dis[u][cp] + 1;
						if (!vis[v][rp])
							 Q1.push(v), Q2.push(rp), vis[v][rp] = 1;		
					}
		        }
		   }
		   vis[u][cp] = 0;	
	}    
}

int main()
{
	freopen("room.in","r",stdin);
	freopen("room.out","w",stdout);
	scanf("%d %d %d", &n, &m, &k);
	int x, u, v;
	for (int i = 1; i <= n; i++)
	     for (int j = 1; j <= k; j++) 
	     {
	     	  scanf("%d", &x);
	     	  if (x) a[i] |= (1 << (j - 1));
		 }
	for (int i = 1; i <= m; i++)
	{
		 scanf("%d %d", &u, &v);
		 e[i].To = v, e[i].nxt = ls[u], ls[u] = i;
		 for (int j = 1; j <= k; j++) 
		 {
		      scanf("%d", &x);
			  if (x) e[i].num |= (1 << (j - 1));	
		 }
	}
	if (n == 1) 
	{
		printf("0\n");
		return 0;
	}
	spfa();
	int ans = inf;
	for (int i = 0; i <= ((1 << k) - 1); i++) ans = min(ans, dis[n][i]);
	if (ans == inf) printf("No Solution");
	           else printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(C++,spfa)