分层图
因为k值很小,所以我们可以建k+1张图。
对于一条边e,起点为u,终点为v,我们可以把上一层图的u与这一层图的v相连,边权为0,表示使用一次免费的机会。而这一层图的u也向v连边,边权为花费。
因为只有k+1个图,所以图与图之间只有k个间隔,故只能使用k次免费的机会,所以我们在这种分层图中跑最短路就可以得到答案ans=dis[ed+k∗n]
。
补充:这一题spfa会被卡,要跑堆优化dijkstra。
哦,还有值得注意的一点,我们可以将每一层的终点向下一层的点连一条0边,可以防止奇葩数据——并不要用k次机会就已经到了终点,所以之后的点不被松弛,故dis[ed+k∗n]!=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;
}