1. 程式人生 > 其它 >洛谷 P3489 [POI2009]WIE-Hexer(二進位制狀壓,分層圖最短路)

洛谷 P3489 [POI2009]WIE-Hexer(二進位制狀壓,分層圖最短路)

傳送門


解題思路

先吐槽一下某谷翻譯能不能把輸入格式也翻譯一下,感覺輸入格式比題目描述都長。。


觀察到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;
}