Gym - 101630J Journey from Petersburg to Mosc (最短路径) (2017–2018, NEERC – Northern Eurasia Finals)

 

 

题意:求最短路径,其中最短路径只算前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;
}

 

发布了402 篇原创文章 · 获赞 67 · 访问量 16万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 点我我会动 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览