大佬的讲解
在郊区有 N 座通信基站,P 条双向电缆,第 i 条电缆连接基站AiAi和BiBi。
特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。
现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费LiLi。
电话公司正在举行优惠活动。
农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。
农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。
求至少用多少钱可以完成升级。
输入格式
第1行:三个整数N,P,K。
第2…P+1行:第 i+1 行包含三个整数Ai,Bi,LiAi,Bi,Li。
输出格式
包含一个整数表示最少花费。
数据范围
0≤K<N≤10000≤K<N≤1000,
1≤P≤100001≤P≤10000,
1≤Li≤10000001≤Li≤1000000
输入样例:
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
输出样例:
4
两种方法:先贴一下分层最短路的两种模板 来源
多开一维数组做法
#include <iostream>
#include <queue>
#include <cstring>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std;
const int N = 1e4 + 10 ;
int n , m , p , k ;
int e[N * 2] , ne[N * 2] , h[N * 2] , idx , w[N * 2] , dis[1100][1100];
bool st[N] ;
const int INF = 0x3f3f3f3f ;
void add(int a , int b , int c)
{
e[idx] = b , w[idx] = c , ne[idx] = h[a] , h[a] = idx ++ ;
}
void spfa()
{
queue<int> q ;
memset(dis , 0x3f , sizeof dis) ;
q.push(1) ;
dis[1][0] = 0;
st[1] = 1 ;
while(q.size())
{
int u = q.front() ;
q.pop() ;
st[u] = 0 ;
for(int i = h[u] ; i != -1 ;i = ne[i])
{
int j = e[i] , z = w[i] ;
int maxn = max(dis[u][0] , z) ;
if(dis[j][0] > maxn)
{
dis[j][0] = maxn ;
if(!st[j])
{
st[j] = 1 ;
q.push(j) ;
}
}
for(int p = 1 ;p <= k ;p ++)
{
maxn = min(dis[u][p - 1] , max(dis[u][p] , z)) ;
if(dis[j][p] > maxn)
{
dis[j][p] = maxn ;
if(!st[j])
{
st[j] = 1 ;
q.push(j) ;
}
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false) ;
cin.tie(0) , cout.tie(0);
cin >> n >> p >> k ;
memset(h , -1 , sizeof h) ;
for(int i = 1 ;i <= p;i ++)
{
int a , b , c ;
cin >> a >> b >> c ;
add(a , b , c) , add(b , a , c) ;
}
spfa() ;
int ans = INF ;
for(int i = 0 ;i <= k ;i ++)
ans = min(ans , dis[n][i]) ;
cout << (ans == 0x3f3f3f3f ? -1 : ans) << endl ;
return 0 ;
}
多建立k层图做法
#include <queue>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e6 + 10000;
const int M = 1e7 + 10 ;
int e[M] , ne[M] , h[N] , w[M] , idx ;
int dis[N] ;
bool st[M] ;
int k , n , p ;
typedef pair<int , int> Pair ;
void add(int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++ ;
}
void spfa()
{
queue<int> q ;
memset(dis , 0x3f , sizeof dis) ;
q.push(1) ;
dis[1] = 0;
st[1] = 1 ;
while(q.size())
{
int u = q.front() ;
q.pop() ;
st[u] = 0 ;
for(int i = h[u] ;i != -1 ;i = ne[i])
{
int j = e[i] ;
int maxn = max(dis[u] , w[i]) ;
if(dis[j] > maxn)
{
dis[j] = maxn;
if(!st[j])
{
st[j] = 1 ;
q.push(j) ;
}
}
}
}
}
int main()
{
int n , p , k ;
cin >> n >> p >> k ;
memset(h , -1 , sizeof h) ;
for(int i = 1 ;i <= p;i ++)
{
int a , b , c ;
scanf("%d%d%d" , &a , &b , &c) ;
add(a , b , c) , add(b , a , c) ;
for(int j = 1 ;j <= k;j ++)
{
add(a + n * j , b + n * j , c) ;
add(b + n * j , a + n * j , c) ;
add(a + n * (j - 1) , b + n * j , 0) ;
add(b + n * (j - 1) , a + n * j , 0) ;
}
}
for(int i = 1 ;i <= k ;i ++)
add(i * n , (i + 1) * n , 0) ;
// 上面这个其实是为了下面输出做一个方便,下面我贴一个不写这个代码的,其他的都是一样的,就只有这里做了一个处理
spfa() ;
printf("%d
" , (dis[(k + 1) * n] == 0x3f3f3f3f ? -1 : dis[(k + 1)* n] ) ) ;
return 0 ;
}
#include<bits/stdc++.h>
using namespace std;
const int N=1000000+10,M=10000000+10;
int n,p,k;
int tot=0;
priority_queue< pair<int ,int> > q;
struct node
{
int ver,nex,edge;
}po[M];
int head[N],dis[N];
bool v[N];
void add(int x,int y,int z)
{
po[++tot].ver=y,po[tot].edge=z;
po[tot].nex=head[x],head[x]=tot;
}
void dijkstra()
{
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
q.push(make_pair(0,1));
while(q.size())
{
int x=q.top().second;
q.pop();
if(v[x]) continue;
v[x]=true;
for(int i=head[x];i;i=po[i].nex)
{
int y=po[i].ver,z=max(po[i].edge,dis[x]);
if(dis[y]>z)
{
dis[y]=z;
q.push(make_pair(-dis[y],y));
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&p,&k);
for(int i=1,x,y,z;i<=p;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
for(int j=1,z1=0;j<=k;j++)
{
add(x+(j-1)*n,y+j*n,z1);
add(y+(j-1)*n,x+j*n,z1);
add(x+j*n,y+j*n,z);
add(y+j*n,x+j*n,z);
}
}
dijkstra();
int ans = 0x3f3f3f3f ;
for(int i = 1 ;i <= k + 1;i ++)
ans = min(ans , dis[i * n]) ;
// 上面那个代码
//for(int i = 1 ;i <= k ;i ++)
// add(i * n , (i + 1) * n , 0) ;
// 不就是在最后的i * n 与 (i + 1) * n 结点通了一条长度为0 的路径,然后在跑最短路的时候,就会自动跑到 dis[(k + 1) * n]
// 也就是说,加上这个代码就直接输出dis[(k + 1) * n] 就行了
// 否则还要来一个k循环,找到min(dis[n][i]) 最小的,从而输出
printf("%d",ans == 0x3f3f3f3f ? -1 : ans);
return 0;
}