2018年9月15日提高組模擬賽 T3 密室
阿新 • • 發佈:2018-12-10
大意
給定一些點的先決條件,問到達終點至少需要經過幾個點
思路
可以把點與點之間的距離看作1,然後跑最短路
需要注意的事判斷的過程中弱國一個一個去判斷速度太過抵消,可以用狀態壓縮的方法表示一種狀態,正常轉移即可
程式碼
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;int n,m,k,l[5001],x,y,tot,key[5001],dis[5001][1025];
struct node{int next,to,need;}e[6001];
struct Node{int u,s;};
inline int read()//輸入優化
{
int f=0,d=1;char c;
while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(register int x){if(x>9)write(x/10);putchar(x%10+48);return;}//輸出優化
inline void addedge()//建邊
{
int u=read(),v=read();
e[++tot].to=v;
e[tot].next=l[u];
l[u]=tot;
for(register int j=0;j<k;j++) e[tot].need|=read()<<j;//用二進位制表示需要那些鑰匙
return;
}
inline void special()//特判所有門都不需要鑰匙的情況
{
int dis[5001];
queue<int>q;
fill(dis+1,dis+1+n,0x3f3f3f3f);
dis[1]=0;q.push(1);
while(q.size())
{
int x=q.front();q.pop();
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(dis[y]>=0x3f3f3f3f)
{
dis[y]=dis[x]+1;
q.push(y);
}
}
}
if(dis[n]>=0x3f3f3f3f) puts("No Solution");else write(dis[n]);
}
inline void work()
{
memset(dis,0x3f,sizeof(dis));
dis[1][key[1]]=0;//初始化
queue<Node>q;
q.push((Node){1,key[1]});
while(q.size())
{
Node x=q.front();q.pop();
for(register int i=l[x.u];i;i=e[i].next)
{
if((x.s&e[i].need)!=e[i].need) continue;//如果它的鑰匙對不上就跳過
int y=e[i].to,s=x.s|key[y];
if(dis[y][s]>=502345657)
{
dis[y][s]=dis[x.u][x.s]+1;
q.push((Node){y,s});
}
}
}
int ans=0x3f3f3f3f;
for(register int i=0;i<(1<<k);i++) ans=min(ans,dis[n][i]);//計算最終狀態
if(ans>=0x3f3f3f3f) puts("No Solution");
else write(ans);//輸出
return;
}
inline void readit()//輸入
{
n=read();m=read();k=read();
for(register int i=1;i<=n;i++)
for(register int j=0;j<k;j++)
key[i]|=read()<<j;
for(register int i=1;i<=m;i++) addedge();
if(!k) special();else work();
}
signed main(){readit();}//主程式