图论训练之十一
https://www.luogu.org/problem/P2939
分层图最短路板子题,好久没写最短路了,算是复习一下吧
根据题意,我们可以发现k的取值范围比较小,所以可以直接用分层图
把一个点强行拆分为k个,原图层代表使用0次升级路的机会,其他的图分别表示使用了1次、2次...k次升级路的机会,然后就可以连边了。考虑每层之间的关系,第i层与第i+1层的边的权值为0,等于用掉了一次升级路的机会。
最终跑一边dijktra,然后求出最小的距离,这道题就做完了
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100100;
const int maxm=500500;
int nextt[maxm*42],w[maxm*42],to[maxm*42],head[maxn*42],cnt=0;
void add(int u,int v,int cost)
{
cnt++;
nextt[cnt]=head[u];
head[u]=cnt;
to[cnt]=v;
w[cnt]=cost;
}
struct node
{
int u,dis;
bool operator<(const node x) const
{
return dis>x.dis;
}
};
priority_queue<node> q;
int dist[maxn*21];
void dij(int s)
{
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
q.push((node){s,0});
while (!q.empty())
{
node fr=q.top();q.pop();
int u=fr.u,dis=fr.dis;
if (dis!=dist[u]) continue;
for (int v=head[u];v;v=nextt[v])
if (dist[to[v]]>dist[u]+w[v])
{
dist[to[v]]=dist[u]+w[v];
q.push((node){to[v],dist[to[v]]});
}
}
}
int n,m,k;
int main()
{
cin>>n>>m>>k;
for (int i=1;i<=m;i++)
{
int u,v,cost;
cin>>u>>v>>cost;
add(u,v,cost);add(v,u,cost);
for (int j=1;j<=k;j++)
{
add(n*j+u,n*j+v,cost);add(n*j+v,n*j+u,cost);
add(n*(j-1)+u,n*j+v,0);add(n*(j-1)+v,n*j+u,0);
}
}
dij(1);
int ans=dist[n];
for (int i=1;i<=k;i++)
ans=min(ans,dist[i*n+n]);
cout<<ans<<endl;
return 0;
}