1. 程式人生 > >JZOJ5459. 【NOIP2017提高A組衝刺11.7】密室

JZOJ5459. 【NOIP2017提高A組衝刺11.7】密室

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

資料範圍

這裡寫圖片描述
這裡寫圖片描述

題解

觀察資料範圍,
k很小,只有10,所以自然地想到狀態壓縮。
將每個房間,每一條邊都變為一個狀態。
fi,s表示到達第i個點,所擁有的鑰匙狀態為s的最小步數。
轉移就是類似spfa。
然而實際上並不用spfa,
因為邊權都是相同的,都為1,直接bfs就好了。

code

#include<cstdio>
#include<cstring> #include<algorithm> #define N 5003 #define P putchar using namespace std; void read(int &n) { int t=0,p=1;char ch; for(ch=getchar();!('0'<=ch && ch<='9');ch=getchar()) if(ch=='-') p=-1; for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
n=t*p; } void write(int x) { if(x>9)write(x/10); P(x%10+48); } int z[13],n,m,k,x,y,nxt[N+1000],to[N+1000],b[N],s[N],v[N+1000],f[N][1024],d[N],head,tail,ss,ans; bool bz[N]; int main() { freopen("room.in","r",stdin); freopen("room.out","w",stdout); z[0]=1; for(int i=1;i<13;i++) z[i]=z[i-1]*2; memset(s,0,sizeof(s)); memset(bz,1,sizeof(bz)); memset(f,127,sizeof(f)); memset(v,0,sizeof(v)); read(n);read(m);read(k); for(int i=1;i<=n;i++) for(int j=0;j<k;j++) read(x),s[i]+=x*z[j]; for(int i=1;i<=m;i++) { read(x);read(y); nxt[i]=b[x]; to[i]=y; b[x]=i; for(int j=0;j<k;j++) read(x),v[i]+=x*z[j]; } f[1][0]=head=bz[d[1]=tail=1]=0; while(head<tail) { x=d[++head]; for(int tt=0;tt<z[k];tt++) { if(f[x][tt]>N)continue; ss=tt|s[x]; for(int i=b[x];i;i=nxt[i]) if((v[i]&ss)>=v[i]) if(f[x][tt]+1<f[to[i]][ss]) { f[to[i]][ss]=f[x][tt]+1; if(bz[to[i]]) { bz[to[i]]=0; d[++tail]=to[i]; } } } bz[x]=1; } ans=2147483647; for(int i=0;i<z[k];i++) ans=ans<f[n][i]?ans:f[n][i]; if(ans>N)printf("No Solution");else write(ans); return 0; }