1. 程式人生 > >nssl1150,jzoj5309-密室【分層建圖,SPFA】

nssl1150,jzoj5309-密室【分層建圖,SPFA】

正題

題目大意

有n個點,m條邊,k種鑰匙。有些點分佈了鑰匙,有些邊需要一些鑰匙才可以通過,求1到n的最短路。

解題思路

將圖分成2k層,每一層用二進位制表示不同的鑰匙情況。然後根據不同情況連邊就好了。 (雙端佇列bfs會莫名其妙WA一個點)

code

#include<cstdio>
#include<queue>
#include<cstring>
#define p(x,y) x*n+y
#define N 5110
#define M 6110
#define MS 1024
using namespace std
; struct node{ int to,next; bool w; }a[MS*(N+M)]; int n,m,k,x,y,w,MAX_State,d[N*MS],tot,ls[N*MS]; bool v[N*MS]; queue<int> q; void addl(int x,int y,int w)//加邊 { a[++tot].to=y; a[tot].next=ls[x]; a[tot].w=w; ls[x]=tot; } void bfs()//SPFA { memset(d,127/3,sizeof(d)); q.push(p(0
,1)); d[p(0,1)]=0;v[p(0,1)]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=ls[x];i;i=a[i].next) { int y=a[i].to; if(d[x]+a[i].w<d[y]) { d[y]=d[x]+a[i].w; if(!v[y]) { v[y]=true
; q.push(y); } } } v[x]=false; } } int main() { scanf("%d%d%d",&n,&m,&k); MAX_State=1<<k; for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) { scanf("%d",&x); if(x) { for(int state=0;state<MAX_State;state++) addl(p(state,i),p((state|(1<<(j-1))),i),0); //不同情況的獲取鑰匙 } } for(int i=1;i<=m;i++) { int state=0; scanf("%d%d",&x,&y); for(int i=1;i<=k;i++) { scanf("%d",&w); state+=w<<(i-1); } for(int j=0;j<MAX_State;j++) if((j&state)==state) addl(p(j,x),p(j,y),1);//滿足鑰匙的情況連邊 } bfs(); int ans; ans=2147483647; for(int j=0;j<MAX_State;j++) ans=min(ans,d[p(j,n)]);//因為沒有要求鑰匙狀態所以取最小的 if(ans>10000) printf("No Solution"); else printf("%d",ans); }