LA4080 Warfare And Logistics (dijkstra+最短路树)

题目链接:https://icpcarchive.ecs.baylor.edu/external/40/4080.pdf

 

题意:有n个顶点,m条边,path[i][j]表示从i到j的最短路径,如果从i到j不连通,则path[i][j] = L;现在求

然后删除一条边,求c1,使得c1 - c 的值最大。

思路:刚看到题目是让各点之间的最短路径和,所以立马想到啦floyd算法求最短路,然后发现还要去掉一条边后求最短路中的最大值,则floyd会超时,所以打算用dijkstra+堆优化做,首先枚举n个顶点求各个顶点之间的最短路径,并求出最短路树,然后枚举每条边,如果这条边在最短路树中,则再求一遍该点的最短路径即可,如果不在最短路树中,则直接利用第一次求得最短路即可。

所谓的最短路树是指在求最短路的同时,记录最短路径。

 

 

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define LL long long
#define inf 1LL << 50
using namespace std;

const int maxn = 110;
const int maxp = 4e3 + 10;

int head[maxp],n,m,L,cnt,vis[maxn],belong[maxp][maxn],p[maxn],delt[maxp];
LL sum[maxn],dist[maxn];//belong[][]记录以s为原点的第i条边是否在s的最短路径中
struct Edge{
    int to,next,w,id;
}edge[maxp];
struct HeapNode{
    int dist,v;
    friend bool operator <(HeapNode A, HeapNode B){
        return A.dist > B.dist;
    }
};

void add(int u, int v, int w, int i){
    edge[cnt].to = v;
    edge[cnt].id = i;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt ++;
}

void dijkstra(int x){
    for(int i = 0; i <= n; i ++) dist[i] = inf, vis[i] = 0;
    memset(p,0,sizeof(p));
    dist[x] = 0;
    priority_queue<HeapNode> q;
    HeapNode no;
    no.dist = 0; no.v = x;
    q.push(no);
    while(!q.empty()){
        no = q.top(); q.pop();
        if(vis[no.v]) continue;
        belong[p[no.v]][x] = 1;
        vis[no.v] = 1;
        for(int i = head[no.v]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(dist[v] > dist[no.v] + edge[i].w){
                dist[v] = dist[no.v] + edge[i].w;
                HeapNode hn;
                p[v] = edge[i].id;
                hn.dist = dist[v]; hn.v = v;
                q.push(hn);
            }
        }
    }
    for(int i = 1; i <= n; i ++){
        if(dist[i] == inf) sum[x] += L;
        else sum[x] += dist[i];
    }
}

int dij(int x){
    for(int i = 0; i <= n; i ++) dist[i] = inf, vis[i] = 0;
    dist[x] = 0;
    priority_queue<HeapNode> q;
    HeapNode no;
    no.dist = 0; no.v = x;
    q.push(no);
    while(!q.empty()){
        no = q.top(); q.pop();
        if(vis[no.v]) continue;
        vis[no.v] = 1;
        for(int i = head[no.v]; i != -1; i = edge[i].next){
            if(delt[edge[i].id]) continue;
            int v = edge[i].to;
            if(dist[v] > dist[no.v] + edge[i].w){
                dist[v] = dist[no.v] + edge[i].w;
                HeapNode hn;
                hn.dist = dist[v]; hn.v = v;
                q.push(hn);
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++){
        if(dist[i] == inf) ans += L;
        else ans += dist[i];
    }
    return ans;
}

int main(){
    while(~scanf("%d%d%d",&n,&m,&L)){
        cnt = 0;
        int u,v,w;
        memset(head,-1,sizeof(head));
        for(int i = 1; i <= m; i ++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w,i);
            add(v,u,w,i);
        }
        memset(belong,0,sizeof(belong));
        for(int i = 1; i <= n; i ++){
            sum[i] = 0;
            dijkstra(i);
        }
        LL ans = 0, Max = 0;
        memset(delt,0,sizeof(delt));
        for(int i = 1; i <= n; i ++) ans += sum[i];
        for(int i = 1; i <= m; i ++){
            delt[i] = 1;
            LL tmp = 0;
            for(int j = 1; j <= n; j ++){
                if(belong[i][j]) tmp += dij(j);
                else tmp += sum[j];
            }
            delt[i] = 0;
            Max = max(Max,tmp);
        }
        printf("%lld %lld\n",ans,Max);
    }
    return 0;
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值