BZOJ1139: [POI2009]Wie

題目大意:大陸上有n個村莊,m條雙向道路,p種怪物,k個鐵匠,每個鐵匠會居住在一個村莊裏,你到了那個村莊後可以讓他給你打造劍,每個鐵匠打造的劍都可以對付一些特定種類的怪物,每條道路上都可能出現一些特定種類的怪物,每條道路都有一個通過所需要的時間,現在要從1走到n,初始的時候你沒有劍,要求在經過一條道路的時候,對於任意一種可能出現在這條道路上的的怪物,你都有已經有至少一把劍可以對付他,求從1走到n的最短時間(打造劍不需要時間)


沒有很多人做的原因是因爲之前題面有問題?

p<=13,那一看就是要記狀態了

然後又要求求最短路

第一下想到狀壓DP,發現沒有拓撲序,所以就只好dijkstra了

d[i][j]記錄到i號點,現在能打怪的狀態是j,最少需要多長時間

轉移的時候判斷一下這條邊能不能走就可以了


雖說200W個點還是有點虛的,不過實際好像跑的還挺快,256ms

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp(x,y,z) (make_pair(make_pair(x,y),z))
#define N 6010
using namespace std;
int a[210];
int to[N],nxt[N],pre[210],cnt,t[N],w[N];
void ae(int ff,int tt,int TT,int ww)
{
	cnt++;
	to[cnt]=tt;
	nxt[cnt]=pre[ff];
	pre[ff]=cnt;
	t[cnt]=TT;
	w[cnt]=ww;
}
int d[210][1<<13];
bool vis[210][1<<13];
priority_queue<pair<pair<int,int>,int>,vector<pair<pair<int,int>,int> >,greater<pair<pair<int,int>,int> > >q;
int n;
int dij()
{
	q.push(mp(0,1,0));
	memset(d,0x3f,sizeof(d));
	d[1][0]=0;
	int i,j,s,x,y,z;
	while(!q.empty())
	{
		s=q.top().first.first;
		x=q.top().first.second;
		y=q.top().second;
		q.pop();
		if(x==n) return s;
		if(vis[x][y]) continue;
		vis[x][y]=true;
		y|=a[x];
		for(i=pre[x];i;i=nxt[i])
		{
			j=to[i];
			if((w[i]|y)!=y) continue;
			if(d[j][y]>s+t[i])
			{
				d[j][y]=s+t[i];
				q.push(mp(d[j][y],j,y));
			}
		}
	}
	return -1;
}
int main()
{
	int m,p,k;
	scanf("%d%d%d%d",&n,&m,&p,&k);
	int i,j,x,y,l,z,o,u;
	for(i=1;i<=k;i++)
	{
		scanf("%d%d",&x,&y);
		for(j=1;j<=y;j++)
		{
			scanf("%d",&z);
			a[x]|=(1<<(z-1));
		}
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&z,&o);
		u=0;
		for(j=1;j<=o;j++)
		{
			scanf("%d",&l);
			u|=(1<<(l-1));
		}
		ae(x,y,z,u);ae(y,x,z,u);
	}
	printf("%d\n",dij());
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章