5459. 【NOIP2017提高A组冲刺11.7】密室
(File IO): input:room.in output:room.out
Time Limits: 1000 ms Memory Limits: 524288 KB Detailed Limits
Description
小X 正困在一个密室里,他希望尽快逃出密室。
密室中有N 个房间,初始时,小X 在1 号房间,而出口在N 号房间。
密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间X 到房间Y 的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。
然而,通过密室的传送门需要耗费大量的时间,因此,小X 希望通过尽可能少的传送门到达出口,你能告诉小X 这个数值吗?
另外,小X 有可能不能逃出这个密室,如果是这样,请输出"No Solution"。
密室中有N 个房间,初始时,小X 在1 号房间,而出口在N 号房间。
密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间X 到房间Y 的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。
然而,通过密室的传送门需要耗费大量的时间,因此,小X 希望通过尽可能少的传送门到达出口,你能告诉小X 这个数值吗?
另外,小X 有可能不能逃出这个密室,如果是这样,请输出"No Solution"。
Input
第一行三个整数N,M,K,分别表示房间的数量、传送门的数量以及钥匙的种类数。
接下来N 行,每行K 个0 或1,若第i 个数为1,则表示该房间内有第i 种钥匙,若第i 个数为0,则表示该房间内没有第i 种钥匙。
接下来M 行,每行先读入两个整数X,Y,表示该传送门是建立在X 号房间,通向Y 号房间的,再读入K 个0 或1,若第i 个数为1,则表示通过该传送门需要i 种钥匙,若第i 个数为0,则表示通过该传送门不需要第i 种钥匙。
接下来N 行,每行K 个0 或1,若第i 个数为1,则表示该房间内有第i 种钥匙,若第i 个数为0,则表示该房间内没有第i 种钥匙。
接下来M 行,每行先读入两个整数X,Y,表示该传送门是建立在X 号房间,通向Y 号房间的,再读入K 个0 或1,若第i 个数为1,则表示通过该传送门需要i 种钥匙,若第i 个数为0,则表示通过该传送门不需要第i 种钥匙。
Output
输出一行一个“No Solution”,或一个整数,表示最少通过的传送门数。
Sample Input
3 3 2
1 0
0 1
0 0
1 3 1 1
1 2 1 0
2 3 1 1
Sample Output
2
Data Constraint
做法: 将K状态压缩后直接bfs即可
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
#define N 5007
using namespace std;
int n, m, k, pre[N], dis[N][], ls[N];
int mi[], tot;
struct edge
{
int to, next, pre;
}e[N * ];
int list[N * ][]; void add(int x, int y, int z)
{
e[++tot].to = y;
e[tot].next = ls[x];
e[tot].pre = z;
ls[x] = tot;
} void init()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = ; i <= n; i++)
{
int x;
pre[i] = ;
for (int j = ; j <= k; j++)
{
scanf("%d", &x);
pre[i] += x * mi[j];
}
} for (int i = ; i <= m; i++)
{
int x, y, z;
scanf("%d%d", &x, &y);
int p = ;
for (int j = ; j <= k; j++)
scanf("%d", &z), p += mi[j] * z;
add(x, y, p);
}
} void pre_work()
{
mi[] = ;
for (int i = ; i <= ; i++)
mi[i] = mi[i - ] * ; } void work()
{
memset(dis, 0x7f7f7f7f, sizeof(dis));
dis[][pre[]] = ;
list[][] = ;
list[][] = pre[];
int head = , tail = ;
while (head < tail)
{
head++;
int now = list[head][];
int p = list[head][];
for (int i = ls[now]; i; i = e[i].next)
{
if ((p | e[i].pre) != p) continue;
int net = p | pre[e[i].to];
if (dis[e[i].to][net] == 0x7f7f7f7f)
{
dis[e[i].to][net] = dis[now][p] + ;
list[++tail][] = e[i].to;
list[tail][] = net;
}
}
}
int ans = 0x7f7f7f7f;
for (int i = ; i <= mi[k + ] - ; i++)
ans = min(ans, dis[n][i]);
if (ans != 0x7f7f7f7f) printf("%d", ans);
else printf("No Solution");
} int main()
{
//freopen("room.in", "r", stdin);
//freopen("room.out", "w", stdout);
pre_work();
init();
work();
}