Description
小X 正困在一个密室里,他希望尽快逃出密室。
密室中有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 种钥匙。
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
Solution
看到 k≤10 ,就想到状压DP——二进制状态!
于是考虑从起点开始做一遍SPFA,用一个二维状态存即可(位置和状态)。
但由于边权为 1 ,没有松弛操作,所以只需 BFS 一遍,输出终点答案即可。
Code
#include<cstdio>
#include<cstring>
using namespace std;
const int N=6001;
struct data
{
int x,y;
}q[N*1000];
int tot,ans=1e9;
int first[N],next[N],en[N],w[N];
int a[N],dis[N][1025];
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline void insert(int x,int y,int z)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
w[tot]=z;
}
int main()
{
int n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)
for(int j=0;j<k;j++) a[i]+=read()<<j;
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=0;
for(int j=0;j<k;j++) z+=read()<<j;
insert(x,y,z);
}
memset(dis,60,sizeof(dis));
int l=dis[1][a[1]]=0,r=1;
q[1].x=1,q[1].y=a[1];
while(l<r)
{
data now=q[++l],t;
for(int i=first[now.x];i;i=next[i])
if((now.y&w[i])==w[i] && dis[now.x][now.y]+1<dis[en[i]][now.y|a[en[i]]])
{
dis[en[i]][now.y|a[en[i]]]=dis[now.x][now.y]+1;
if(en[i]==n) ans=min(ans,dis[en[i]][now.y|a[en[i]]]);
t.x=en[i],t.y=now.y|a[en[i]];
q[++r]=t;
}
}
if(ans==1e9) puts("No Solution"); else printf("%d",ans);
return 0;
}