洛谷 P3489 [POI2009]WIE-Hexer(二進位制狀壓,分層圖最短路)
阿新 • • 發佈:2021-09-28
傳送門
解題思路
先吐槽一下某谷翻譯能不能把輸入格式也翻譯一下,感覺輸入格式比題目描述都長。。
觀察到p非常小,於是考慮狀態壓縮,將當前能打的怪物壓縮成一個二進位制數。
按照每個二進位制數分層,一共分得 2^13=8192 層。
邊全部存下會MLE,所以考慮在轉移的時候判斷一下,只有出邊的狀態是現在狀態的子集時才進行轉移。
AC程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> using namespace std; const int maxn=2e6+5; const int maxm=1e4+5; int cnt,n,m,k,p[maxn],P,dis[maxn],value[maxn]; struct node{ int v,next,w,f; }e[maxm]; void insert(int u,int v,int w,int f){ cnt++; e[cnt].v=v; e[cnt].w=w; e[cnt].f=f; e[cnt].next=p[u]; p[u]=cnt; } void dij(){ set<pair<int,int> > s; dis[value[0]*n]=0; s.insert(make_pair(0,value[0]*n)); while(!s.empty()){ int id=s.begin()->second; s.erase(s.begin()); int state=id/n; int u=id%n; if(u==n-1){ cout<<dis[id]<<endl; return; } for(int i=p[u];i!=-1;i=e[i].next){ if((e[i].f&state)!=e[i].f) continue; int v=e[i].v; v=(state|value[v])*n+v; if(dis[v]>dis[id]+e[i].w){ s.erase(make_pair(dis[v],v)); dis[v]=dis[id]+e[i].w; s.insert(make_pair(dis[v],v)); } } } cout<<-1; } template<class T>inline void read(T &x) { x=0;register char c=getchar();register bool f=0; while(!isdigit(c))f^=c=='-',c=getchar(); while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); if(f)x=-x; } int main(){ ios::sync_with_stdio(false); memset(p,-1,sizeof(p)); memset(dis,0x3f,sizeof(dis)); read(n);read(m);read(P);read(k); for(int i=1;i<=k;i++){ int w,q; read(w);read(q); w--; while(q--){ int k; read(k); value[w]|=(1<<(k-1)); } } for(int i=1;i<=m;i++){ int u,v,w,q,res=0; read(u);read(v);read(w);read(q); u--;v--; while(q--){ int x; read(x); res|=(1<<(x-1)); } insert(u,v,w,res); insert(v,u,w,res); } dij(); return 0; }