题目描述
在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站 Ai 和 Bi。
特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。
现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费 Li。
电话公司正在举行优惠活动。
农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。
农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。
求至少用多少钱可以完成升级。
输入格式
第 1 行:三个整数 N,P,K。
第 2…P+1 行:第 i+1 行包含三个整数 Ai,Bi,Li。
输出格式
包含一个整数表示最少花费。
若 1 号基站与 N 号基站之间不存在路径,则输出 −1。
输入样例
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
题解
这道题的主要做法为分层图,按照之前所讲,很明显这道题有两种做法,压维度直接连边或者加维
首先先来说第一种做法
第
i
i
i层图中的第
j
j
j号点即为使用了
i
i
i次免费升级后,到达
j
j
j号点所花费的最小代价。
首先思考几何图是一个怎样的,对于每一层图,数据中给定的边在这一层图中都应是连通的,花费的代价都为1,那么就需要考虑层与层之间的关系,从第
i
i
i层的点
a
a
a到第
i
+
1
i+1
i+1层的点
b
b
b花费的代价应为0,因为跨层是不需要花费代价的,这个操作也可以理解为用了免费的一次机会
连好图后跑一遍Dijkstra即可
code
#include <bits/stdc++.h>
using namespace std;
const int N=1000050;
int n,K,m,tot,head[N],s,t;
struct Star
{
int nxt,to,val;
}edge[2*N];
void Lian(int x,int y,int z)
{
tot++;
edge[tot].nxt=head[x];
edge[tot].to=y;
edge[tot].val=z;
head[x]=tot;
}
int dis[N],vis[N];
struct Point
{
int dd,p;
bool operator<(const Point &x) const{
return dd>x.dd;
}
};
void dijkstra()
{
memset(dis,63,sizeof(dis));
priority_queue <Point> que;
dis[1]=0;
Point a;
a.p=1;
a.dd=0;
que.push(a);
while(!que.empty())
{
a=que.top();
que.pop();
int x=a.p;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(dis[y]>max(dis[x],edge[i].val))
{
dis[y]=max(dis[x],edge[i].val);
a.p=y;
a.dd=dis[y];
que.push(a);
}
}
}
}
int main()
{
cin>>n>>m>>K;
s=1,t=n;
for(int i=1;i<=m;i++){
int l,r,q;
cin>>l>>r>>q;
Lian(l,r,q);Lian(r,l,q);
for(int j=1;j<=K;j++)
{
Lian(j*n+l,j*n+r,q);
Lian(j*n+r,j*n+l,q);
Lian((j-1)*n+l,j*n+r,0);
Lian((j-1)*n+r,j*n+l,0);
}
}
dijkstra();
if(dis[K*n+t]!=1061109567)
printf("%d",dis[K*n+t]);
else printf("-1");
return 0;
}
那么第二种做法,其实与建图大同小异,在dis,vis数组中多开一个维度,并在结构体中多存一个值表示在第几层,跑最短路过程中多进行一个转移层与层之间的转移方程即可
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=10010;
int tot,n,T,head[N],m,vis[N][N],dis[N][N];
struct node{
int p,d,c;
bool operator<(const node &X)const{
return d>X.d;
}
};
struct Star
{
int nxt,to,val;
}edge[2*M];
void Lian(int x,int y,int z)
{
tot++;
edge[tot].to=y;
edge[tot].nxt=head[x];
edge[tot].val=z;
head[x]=tot;
}
void dijkstra()
{
priority_queue<node> q;
for(int i=1;i<=n;i++)
for(int j=0;j<=T;j++)
dis[i][j]=1e9;
dis[1][0]=0;
node a;
a.d=0,a.p=1,a.c=0;
q.push(a);
while(!q.empty())
{
a=q.top();
q.pop();
int x=a.p,z=a.c;
if(vis[x][z]) continue;
vis[x][z]=1;
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(dis[y][z]>max(dis[x][z],edge[i].val))
{
dis[y][z]=max(dis[x][z],edge[i].val);
if(!vis[y][z])
{
a.d=dis[y][z],a.p=y,a.c=z;
q.push(a);
}
}
if(z<T&&dis[y][z+1]>dis[x][z])
{
dis[y][z+1]=dis[x][z];
if(!vis[y][z+1])
{
a.d=dis[y][z+1],a.p=y,a.c=z+1;
q.push(a);
}
}
}
}
}
int main()
{
cin>>n>>m>>T;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
Lian(x,y,z);
Lian(y,x,z);
}
dijkstra();
if(dis[n][T]!=1e9) printf("%d",dis[n][T]);
else printf("-1");
return 0;
}