【图论】[luoguP3905]道路重建

题目

一个变形的最短路问题 我们可以在每次寻找最短路的时候都去维护一个当前的最小花费 当我们知道当前找的这条边不是被摧毁的边的时候 我们则需要在pay[edge[i].to]和pay[u]中找一个较小的而不用再考虑这条边的长度

用的刚学的堆优化dijkstra
代码如下



#include<iostream>
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<string>

    using namespace std;
    #define in = read()
    typedef long long ll;
    const ll size = 500000 + 10000;
    const ll size2 = 1000 + 10;

        struct point{   ll next,to,dis;}edge[size];
        priority_queue <pair<ll , ll> , vector<pair<ll , ll> > , greater<pair<ll , ll> > > q;

            ll n,m,d,Beginn,Endd;
            ll site;
            ll head[size],dis[size],pay[size];
            bool exist[size],need[size2][size2];

inline ll read(){
        ll num = 0 , f = 1;   char ch = getchar();

        while(!isdigit(ch)){
                if(ch == '-')   f = -1;
                ch = getchar();
        }

        while(isdigit(ch)){
                num = num*10 + ch - '0';
                ch = getchar();
        }

        return num*f;
}

inline void add(ll x, ll y, ll z){
        edge[++site].next = head[x];
        edge[site].to = y;
        edge[site].dis = z;
        head[x] = site;
}

int main(){
        n in;   m in;
        for(int i=1;i<=m;i++){
                ll x,y,z;   x in;   y in;   z in;
                add(x,y,z);   add(y,x,z);
        }
        d in;
        for(int i=1;i<=d;i++){
                ll x,y;   x in;   y in;
                need[x][y] = need[y][x] = true;
        }
        Beginn in;   Endd in;
        memset(dis,127/3,sizeof(dis));    dis[Beginn] = 0;
        memset(pay,127/3,sizeof(pay));    pay[Beginn] = 0;

        pair<ll , ll> x;
        q.push(make_pair(0,Beginn));
        while(!q.empty()){
                x = q.top();    q.pop();    ll u = x.second;
                if(exist[u])    continue;
                exist[u] = true;
                for(int i=head[u];i!=0;i=edge[i].next)
                        if(edge[i].dis + dis[u] < dis[edge[i].to]){
                                dis[edge[i].to] = edge[i].dis + dis[u];
                                if(need[u][edge[i].to])
                                        pay[edge[i].to] = min(pay[edge[i].to],edge[i].dis + pay[u]);
                                else
                                        pay[edge[i].to] = min(pay[edge[i].to],pay[u]);
                                q.push(make_pair(dis[edge[i].to],edge[i].to));
                        }
                exist[u] = false;
        }

        printf("%d",pay[Endd]);
}


//COYG
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值