uva1416 - Warfare And Logistics 最短路树优化

The army of United Nations launched a new wave of air strikes on terroristforces. The objective of the mission is to reduce enemy's logistical mobility. Each airstrike will destroy a path and therefore increase the shipping cost of the shortest pathbetween two enemy locations. The maximal damage is always desirable.

Let's assume that there are n enemy locations connected by m bidirectional paths,each with specific shipping cost. Enemy's total shipping cost is given as c = $ \sum^{​{n}}_{​{i=1}}$$ \sum^{​{n}}_{​{j=1}}$path(i, j). Here path(i, j) is the shortest path between locations i and j. In case i and j are not connected, path(i, j) = L. Each air strike can only destroy one path. The total shipping cost after the strike is noted as c'. In order to maximizedthe damage to the enemy, UN's air force try to find the maximal c' - c.

Input 

The first line ofeach input case consists ofthree integers: n, m, and L. 1 < n$ \le$100,1$ \le$m$ \le$1000, 1$ \le$L$ \le$10$\scriptstyle \wedge$8. Each ofthe following m lines contains three integers: a,b, s, indicating length of the path between a and b.

Output 

For each case, output the total shipping cost before the air strike and the maximaltotal shipping cost after the strike. Output them in one line separated by a space.

Sample Input 

4  6  1000
1  3  2
1  4  4
2  1  3
2  3  3
3  4  1
4  2  2

Sample Output 

28  38

  N个节点M条边的无向图,每条边上有个正权,c为每对节点的最短路长度之和。要求删除一条边后使得新的c值c'最大。不连通的两点最短路长度视为L。输出c'。

  如果用floyd,每删一条边计算一次,复杂度O(n^3m)。如果用N次dijkstra计算单源最短路,时间复杂度为O(nm^2logn)。

  在源点确定的情况下,只要最短路树不被破坏,起点到所有点的距离都不会改变,也就是只有删除最短路树上的N-1条边中的某条,最短路树才需要重新计算。因此每个源点,最多只要求N次而不是M次单源最短路,时间复杂度变为O(n^2mlohn)。

  注意有坑,可能有重边,这时要用第二短边代替。

  以前写最短路都没有写成结构体这样,并且加边也不像这个结构体里写的这样。这题修改边的时候就发现这样结构化的模版的好处了,有很多功能而且方便调用。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 110
#define MAXM 2000010
#define MAXNODE 105
#define MOD 100000
#define SIGMA_SIZE 4
typedef long long LL;
using namespace std;
int N,M,L,sum_single[MAXN],used[MAXN][MAXN][MAXN],idx[MAXN][MAXN];
vector<int> g[MAXN][MAXN];
struct Edge{
    int u,v,dist;
};
struct HeapNode{
    int u,d;
    bool operator < (const HeapNode& rhs) const{
        return d>rhs.d;
    }
};
struct Dijkstra{
    int n,m;
    vector<Edge> edges;
    vector<int> G[MAXN];
    bool done[MAXN];
    int d[MAXN];
    int p[MAXN];

    void init(int n){
        this->n=n;
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }
    void add_edge(int u,int v,int dist){
        edges.push_back((Edge){u,v,dist});
        m=edges.size();
        G[u].push_back(m-1);
    }
    void dijkstra(int s){
        priority_queue<HeapNode> q;
        for(int i=0;i<n;i++) d[i]=INF;
        d[s]=0;
        q.push((HeapNode){s,0});
        memset(done,0,sizeof(done));
        while(!q.empty()){
            HeapNode x=q.top();
            q.pop();
            int u=x.u;
            if(done[u]) continue;
            done[u]=true;
            int L=G[u].size();
            for(int i=0;i<L;i++){
                Edge& e=edges[G[u][i]];
                if(e.dist>0&&d[e.v]>d[u]+e.dist){
                    d[e.v]=d[u]+e.dist;
                    p[e.v]=G[u][i];
                    q.push((HeapNode){e.v,d[e.v]});
                }
            }
        }
    }
}solver;
int cal(){
    int ret=0;
    memset(used,0,sizeof(used));
    for(int src=0;src<N;src++){
        solver.dijkstra(src);
        sum_single[src]=0;
        for(int i=0;i<N;i++){
            if(i!=src){
                int fa=solver.edges[solver.p[i]].u;
                used[src][fa][i]=used[src][i][fa]=1;    //fa->i是以src为源最短路树上的边
            }
            sum_single[src]+=(solver.d[i]==INF?L:solver.d[i]);
        }
        ret+=sum_single[src];
    }
    return ret;
}
int cal_new(int a,int b){
    int ret=0;
    for(int src=0;src<N;src++){
        if(!used[src][a][b]) ret+=sum_single[src];  //如果不在最短路树上src到各个点的最短路不变
        else{
            solver.dijkstra(src);
            for(int i=0;i<N;i++) ret+=(solver.d[i]==INF?L:solver.d[i]);
        }
    }
    return ret;
}
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&N,&M,&L)!=EOF){
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++) g[i][j].clear();
        solver.init(N);
        int u,v,dist;
        while(M--){
            scanf("%d%d%d",&u,&v,&dist);
            u--;
            v--;
            g[u][v].push_back(dist);
            g[v][u].push_back(dist);
        }
        for(int u=0;u<N;u++)
            for(int v=u+1;v<N;v++) if(!g[u][v].empty()){
                sort(g[u][v].begin(),g[u][v].end());
                solver.add_edge(u,v,g[u][v][0]);
                idx[u][v]=solver.m-1;
                solver.add_edge(v,u,g[u][v][0]);
                idx[v][u]=solver.m-1;
            }
        int ans1=cal(),ans2=-1;
        for(int i=0;i<N;i++)
            for(int j=i+1;j<N;j++) if(!g[i][j].empty()){
                int& e1=solver.edges[idx[i][j]].dist;
                int& e2=solver.edges[idx[j][i]].dist;
                if(g[i][j].size()==1) e1=e2=-1;
                else e1=e2=g[i][j][1];
                ans2=max(ans2,cal_new(i,j));
                e1=e2=g[i][j][0];
            }
        printf("%d %d\n",ans1,ans2);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值