版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/84034914
题意:求最短路径,其中最短路径只算前K大的边。
解题思路:枚举所有边权,然后对原图重新建图,如果边权小于当前枚举值,那么把他权值置为0,大于的话,让他减去当前枚举的大小。然后跑最短路即可。最后用d[N]+K*c[i]更新答案即可。
以下是简单的证明:
首先只算前k大的边的最短路肯定比真正的最短路要小。
假设第K+1大的边为X,那么在最短路中,小于等于X的边的权值可以视为0.
所以我们只需要枚举第K+1大的边的权值即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=3005;
struct edge{
int u,v,next;
ll w;
}ye[MAXN*2],e[MAXN*2];
int head[MAXN],edge_num;
void insert_edge(int u,int v,ll w){
ye[edge_num].u=u;
ye[edge_num].v=v;
ye[edge_num].w=w;
ye[edge_num].next=head[u];
head[u]=edge_num++;
}
int N,M,K;
ll c[MAXN*2];
void rebuild(ll x){
for(int i=0;i<edge_num;i++){
e[i]=ye[i];
if(ye[i].w<x){
e[i].w=0;
}
else
e[i].w-=x;
}
}
ll d[MAXN];
bool vis[MAXN];
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> >> que;
ll dij(){
memset(d,0x3f,sizeof(d));
memset(vis,0,sizeof(vis));
que.push({0,1});
d[1]=0;
while(!que.empty()){
auto tp=que.top();
que.pop();
int u=tp.second;
if(vis[u])
continue;
vis[u]=1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(d[v]>d[u]+e[i].w){
d[v]=d[u]+e[i].w;
que.push({d[v],v});
}
}
}
return d[N];
}
int main()
{
memset(head,-1,sizeof(head));
edge_num=0;
scanf("%d%d%d",&N,&M,&K);
int u,v;
ll w;
for(int i=0;i<M;i++){
scanf("%d%d%lld",&u,&v,&w);
insert_edge(u,v,w);
insert_edge(v,u,w);
c[i]=w;
}
rebuild(0);
ll ans=dij();
for(int i=0;i<M;i++){
rebuild(c[i]);
ll p=dij();
ans=min(ans,p+K*c[i]);
}
printf("%lld\n",ans);
return 0;
}