[NOIP模拟赛][分层图][状态压缩] 密室

题面

题目描述
\(X\) 正困在一个密室里,他希望尽快逃出密室。

密室中有 \(N\) 个房间,初始时,小 \(X\)\(1\) 号房间,而出口在 \(N\) 号房间。

密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间 \(X\) 到房间 \(Y\) 的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。

然而,通过密室的传送门需要耗费大量的时间,因此,小 \(X\) 希望通过尽可能少的传送门到达出口,你能告诉小 \(X\) 这个数值吗?

另外,小 \(X\) 有可能不能逃出这个密室,如果是这样,请输出 \(No\ Solution\)


我们可以利用分层图的思想,将当前获得的钥匙有哪些作为分层的依据进行转移,
我们发现 \(k \lt 10\),想到可以状态压缩表示钥匙数,
然后这题就差不多解决了

代码:

// 状压二进制枚举当前钥匙的状态
// BFS 转移 Dis

# include <iostream>
# include <cstdio>
# include <cstring>
# include <queue>
# define MAXN 6005
# define MAXM 6005

struct edge{
	int v, next, key;
}e[MAXM];
struct node{
	int id, key;
};
int hd[MAXN], cntE; int dis[MAXN]; bool inQ[1<<11][MAXN];
int hasKey[MAXN]; // 表示每个节点有的钥匙
// int reqKey[MAXM]; // 表示每个传送门需要的钥匙
// if(nowKey & reqKey == reqKey) then
int f[1<<11][MAXN];

void AddE(int u, int v, int reqKey){
	e[++cntE] = (edge){v, hd[u], reqKey};
	hd[u] = cntE;
}

int main(){
	int n, m, k;

	scanf("%d%d%d", &n, &m, &k);

	for(int i = 1; i <= n; i++){
		for(int j = 1, x; j <= k; j++){
			hasKey[i] <<= 1;
			scanf("%d", &x);
			hasKey[i] += x;
		}
	}

	for(int i = 1, x, y, req; i <= m; i++){
		req = 0;
		scanf("%d%d", &x, &y);
		for(int j = 1, xx; j <= k; j++){
			req <<= 1;
			scanf("%d", &xx);
			req += xx;
		}
		AddE(x, y, req);
	}

	std::queue<node>Q;
	memset(f, 0x3f, sizeof(f));
	f[hasKey[1]][1] = 0; Q.push((node){1, hasKey[1]});
	inQ[hasKey[1]][1] = 1;

	while(Q.size()){
		node now = Q.front(); Q.pop();
		inQ[now.key][now.id] = 0;

		for(int i = hd[now.id], nxtSta; i; i = e[i].next){
			nxtSta = now.key | hasKey[e[i].v];
			if((e[i].key & now.key) == e[i].key && f[nxtSta][e[i].v] > f[now.key][now.id] + 1){
				f[nxtSta][e[i].v] = f[now.key][now.id] + 1;
				if(!inQ[nxtSta][e[i].v]){
					inQ[nxtSta][e[i].v] = 1;
					Q.push((node){e[i].v, nxtSta});
				}
			}
		}
	}

	int ans = 0x3f3f3f3f;
	for(int i = 0; i < (1<<k); i++){
		ans = std::min(ans, f[i][n]);
	}

	if(ans == 0x3f3f3f3f){
		printf("No Solution");
	}
	else{
		printf("%d", ans);
	}

	return 0;
}
posted @ 2020-09-17 19:03  ChPu437  阅读(158)  评论(0编辑  收藏  举报