P4568 [JLOI2011]飞行路线 【分层图】【模板】

分层图

因为k值很小,所以我们可以建k+1张图。

对于一条边e,起点为u,终点为v,我们可以把上一层图的u与这一层图的v相连,边权为0,表示使用一次免费的机会。而这一层图的u也向v连边,边权为花费。

因为只有k+1个图,所以图与图之间只有k个间隔,故只能使用k次免费的机会,所以我们在这种分层图中跑最短路就可以得到答案ans=dis[ed+kn]

补充:这一题spfa会被卡,要跑堆优化dijkstra。

哦,还有值得注意的一点,我们可以将每一层的终点向下一层的点连一条0边,可以防止奇葩数据——并不要用k次机会就已经到了终点,所以之后的点不被松弛,故dis[ed+kn]!=ans

代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int Max = 110005;
const int inf = 1e9;
int n,m,k,s,t;
int a,b,c;
int d[Max];
vector<pair<int,int> > E[Max];
void init()
{
	for(int i=0;i<Max;i++)
	{
		d[i]=inf;
		E[i].clear();
	}
}
void dij()
{
	priority_queue<pair<int,int> > Q;
	d[s]=0;
	Q.push(make_pair(-d[s],s));
	while(!Q.empty())
	{
		int now = Q.top().second;
		Q.pop();
		if(now == t) return ;
		for(int i=0;i<E[now].size();i++)
		{
			int v = E[now][i].first;
			if(d[v] > d[now]+E[now][i].second)
			{
				d[v] = d[now] + E[now][i].second;
				Q.push(make_pair(-d[v],v));
			}
		}
	}
}
int main()
{
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		init();
		scanf("%d%d",&s,&t);
		s++,t++;
		while(m--)
		{
			scanf("%d%d%d",&a,&b,&c);
			a++,b++;
			
			for(int i=1;i<=k;i++)
			{
				E[a+(i-1)*n].push_back(make_pair(b+i*n,0));
				E[b+(i-1)*n].push_back(make_pair(a+i*n,0));
				E[a+i*n].push_back(make_pair(b+i*n,c));
				E[b+i*n].push_back(make_pair(a+i*n,c));
			}
			E[a].push_back(make_pair(b,c));
			E[b].push_back(make_pair(a,c));
		}
		for(int i=1;i<=k;i++)
		{
			E[t+(i-1)*n].push_back(make_pair(t+i*k,0));
		}
		dij();
		printf("%d\n",d[t+k*n]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40816078/article/details/82431588
今日推荐