P4568 [JLOI2011]飛行路線

題意:給你一張無向圖,現在你可以把圖中至多$k&條邊的邊權變爲0.求此時的最短路。

解法:最短路+DP(還有個更爲熟知的標籤叫做分層圖emmm)

dp[i][j]爲從1->i用了j條免費邊後的最短路,那麼:

                                                      dp[i][j]=min(dp[u[k]][j-1],dp[u[k]][j]+w[k])

dp[u[k]][j-1]狀態轉移:此時邊k被作爲免費邊使用。

dp[u[k]][j]+w[k]狀態轉移:很顯然這是一個最短路。

其中k所有終點爲i的邊的序號。

Code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#define ri register int
using namespace std;

const int MAXN=100020,KMAXN=55,INF=1310668019;
int n,m,k,s,t,u[MAXN],v[MAXN],w[MAXN],fst[MAXN],nxt[MAXN],dis[MAXN][KMAXN],book[MAXN];

inline int read()
{
	int x=0;
	char ch=getchar();
	while(ch<'0'||'9'<ch)	ch=getchar();
	while('0'<=ch&&ch<='9')
	{
		x=(x <<3)+(x <<1)+(int)(ch-'0');
		ch=getchar();
	}
	return x;
}

struct node{
	int num,c;
};
priority_queue<node>Q;
bool operator<(const node &a,const node &b)
{
	return a.c > b.c;
}

void Dijkstra(int cnt)//cnt:當前使用的免費機會的次數 
{
	memset(book,0,sizeof(book));
	for(ri i=0;i<=n-1;i++)	 dis[i][cnt]=INF;
	dis[s][cnt]=0;
	Q.push((node){s,0});
	while(!Q.empty())
	{
		int x=Q.top().num; Q.pop();
		if(book[x])	 continue;
		book[x]=1;
		for(ri k=fst[x];k>0;k=nxt[k])
		{
			if(cnt==0&&dis[v[k]][cnt]>dis[u[k]][cnt]+w[k])
			//cnt=0時跑出來的dis[][cnt]應爲原圖的最短路 
			{
				dis[v[k]][cnt]=dis[u[k]][cnt]+w[k];
				Q.push((node){v[k],dis[v[k]][cnt]});
			}
			if(cnt>0)
			//cnt>0時dis[v[k]][cnt]可由dis[u[k]][cnt-1]和dis[u[k]][cnt]+w[k]這兩種狀態轉移而來。需分類討論。 
			{
				if(dis[v[k]][cnt]>dis[u[k]][cnt-1])
				{
					dis[v[k]][cnt]=dis[u[k]][cnt-1];
					Q.push((node){v[k],dis[v[k]][cnt]});
				}
				if(dis[v[k]][cnt]>dis[u[k]][cnt]+w[k])
				{
					dis[v[k]][cnt]=dis[u[k]][cnt]+w[k];
					Q.push((node){v[k],dis[v[k]][cnt]});
				}
			}
		}
	}
}

int main()
{
	n=read(),m=read(),k=read(),s=read(),t=read();
	m <<=1;
	for(ri i=1;i<=m;i+=2)
	{
		u[i]=read(),v[i]=read(),w[i]=read();
		nxt[i]=fst[u[i]],fst[u[i]]=i;
		u[i+1]=v[i],v[i+1]=u[i],w[i+1]=w[i];
		nxt[i+1]=fst[u[i+1]],fst[u[i+1]]=i+1;
	}
	for(ri i=0;i<=k;i++)
	//dis[][i]從dis[][i-1]和dis[][i]轉移而來,故跑k+1遍dijk。這邊跑完後更新出dis[][i]。
	//這樣不斷更新知道更新完 dis[][k],dis[n][k]即爲答案。 
		Dijkstra(i);
	cout<<dis[t][k];
	return 0;
}

 

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