【Heap-dijkstra】CDOJ1639 雲中誰寄錦書來?雁字回時,月滿西樓。

題意: 在n個點m條邊的無向圖上,有k個出口 從起點出發,每到一個點(包括起點),該點連出的邊中有d條會被封鎖 求最壞狀況下到達出口的最短路html

題解: 該題爲dijkstra算法的拓展算法

因爲求最壞狀況下的最短路,對於每一個點,顯然最優的前d條邊不能走post

對於邊u->v,必然要先獲得v到出口的最壞狀況下的最短路 才能獲得u通過該邊再到出口的最壞狀況下的最短路,也就是該邊對於u的價值 因此要從出口往回考慮spa

令f[i]表示i到出口的最壞狀況下的最短路 同dijkstra算法同樣,每一個點i能夠分爲f[i]已肯定的和f[i]未肯定的 初始時天然是對於每一個出口x,f[x]=0已肯定code

對於f[v]已肯定的點v,將邊權爲w的邊u->v以f[v]+w爲關鍵字加入小根堆中htm

對於每一個點i還要記錄cnt[i]=k,表示到i後,i連出的最優的前k條邊已被封鎖blog

每次取出堆頂對應的邊u->v(若f[u]已肯定直接彈出) 則該邊爲u連出的(除已被封鎖的邊外)最優的邊 若cnt[u]<d,該邊必然會被封鎖,那麼將cnt[u]加1,彈出堆頂 若cnt[u]=d,那麼能夠肯定f[u]=f[v]+w,再用u更新連向u的邊,彈出堆頂jade

重複這一過程直到肯定f[0]的值,該值即爲答案string

 

不妨思考下爲什麼不從起點開始考慮it

若從起點開始考慮,令f[i]表示從起點到i的最壞狀況下的最短路 對於f[u]已肯定的點u,將邊權爲w的邊u->v以f[u]+w爲關鍵字加入小根堆中 每次取出堆頂對應的邊u->v(若f[v]已肯定直接彈出) 若cnt[u]<d,該邊必然會被封鎖,那麼將cnt[u]加1,彈出堆頂 若cnt[u]=d,能夠肯定f[v]=f[u]+w,再用v更新v連向的邊,彈出堆頂

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct Edge{
	int u,v,d;
};
bool operator < (const Edge &a,const Edge &b){
	return a.d>b.d;
}
priority_queue<Edge>Heap;
int n,m,K,d,f[100010],cnts[100010];
int v[2000010],__next[2000010],first[100010],w[2000010],e;
void AddEdge(int U,int V,int W){
	v[++e]=V;
	w[e]=W;
	__next[e]=first[U];
	first[U]=e;
}
int main(){
	int x,y,z;
	scanf("%d%d%d%d",&n,&m,&K,&d);
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&x,&y,&z);
		AddEdge(x,y,z);
		AddEdge(y,x,z);
	}
	memset(f,0x7f,sizeof(f));
	for(int i=1;i<=K;++i){
		scanf("%d",&x);
		f[x]=0;
		cnts[x]=d+1;
		for(int j=first[x];j;j=__next[j]){
			Heap.push((Edge){v[j],x,w[j]});
		}
	}
	while(!Heap.empty()){
		Edge E=Heap.top(); Heap.pop();
		++cnts[E.u];
		if(cnts[E.u]==d+1){
			f[E.u]=E.d;
			for(int i=first[E.u];i;i=__next[i]){
				if(cnts[v[i]]<=d){
					Heap.push((Edge){v[i],E.u,f[E.u]+w[i]});
				}
			}
		}
	}
	printf("%d\n",f[0]>2000000000 ? -1 : f[0]);
	return 0;
}

轉載於:https://www.cnblogs.com/autsky-jadek/p/6910375.html