1. 程式人生 > >2018年9月15日提高組模擬賽 T3 密室

2018年9月15日提高組模擬賽 T3 密室

大意

給定一些點的先決條件,問到達終點至少需要經過幾個點

思路

可以把點與點之間的距離看作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();}//主程式