[BZOJ2763][JLOI2011]飞行路线

bzoj

sol

很显然设(f_{i,j})表示在(i)号点已经使用了(j)次免费的最小费用。
转移就是两种,使用免费或者是不使用。
相当于就是(nk)个点的最短路。
(Dijkstra)即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define pii pair<int,int>
#define mk make_pair
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 2e5+5;
int n,m,K,S,T,to[N],nxt[N],ww[N],head[N],cnt,dis[N],vis[N],ans=2e9;
priority_queue<pii,vector<pii>,greater<pii> >Q;
void link(int u,int v,int w)
{
	to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;
	head[u]=cnt;
}
void dijkstra()
{
	memset(dis,63,sizeof(dis));
	dis[S]=0;Q.push(mk(0,S));
	while (!Q.empty())
	{
		int x=Q.top().second;Q.pop();
		if (vis[x]) continue;vis[x]=1;
		int u=x%n,t=x/n;
		for (int e=head[u];e;e=nxt[e])
		{
			int v=to[e];
			if (dis[v+t*n]>dis[x]+ww[e])
				dis[v+t*n]=dis[x]+ww[e],Q.push(mk(dis[v+t*n],v+t*n));
			if (dis[v+(t+1)*n]>dis[x]&&t<K)
				dis[v+(t+1)*n]=dis[x],Q.push(mk(dis[v+(t+1)*n],v+(t+1)*n));
		}
	}
}
int main()
{
	n=gi();m=gi();K=gi();S=gi();T=gi();
	for (int i=1;i<=m;++i)
	{
		int u=gi(),v=gi(),w=gi();
		link(u,v,w);link(v,u,w);
	}
	dijkstra();
	for (int i=0;i<=K;++i)
		ans=min(ans,dis[T+i*n]);
	printf("%d
",ans);return 0;
}
原文地址:https://www.cnblogs.com/zhoushuyu/p/8663437.html