uva 1416 Warfare And Logistics (最短路树)

uva 1416 Warfare And Logistics

Description

The army of United Nations launched a new wave of air strikes on terrorist forces. The objective of the mission is to reduce enemy’s logistical mobility. Each air strike will destroy a path and therefore increase the shipping cost of the shortest path between 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 = ∑ni=1∑nj=1path(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 maximized the 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≤100 , 1≤m≤1000 , 1≤L≤10∧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 maximal total 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等于没对节点的最短路长度之和。例如n=3时,c=d(1,1)+d(1,2)+d(1,3)+d(2,1)+d(2,2)+d(2,3)+d(3,1)+d(3,2)+d(3,3)。要求删除一条边后使得新的c值最大。不连通的两点间距离视为L。

解题思路:如果删除每一条边后求一次最短路,肯定会超时。其实有一些边,删了之后对c的值是没有影响的,这些边,就是游离在最短路之外的边。所以我们只要找出在最短路上的边,然后枚举删除这些边,就行了。最短路上的n个点,和n - 1条边构成最短路树。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;

const int N = 200;
const int M = 5005;
const int INF = 0x3f3f3f3f;;
typedef long long ll;
int n, m, l;
ll Dis[N];

struct Edge{
    int from,to;
    ll dist;
    int flag;
};
struct HeapNode{
    int d,u;
    bool operator < (const HeapNode& rhs) const{
        return d > rhs.d;
    }
};  

struct Dijkstra{
    int n,m;              //点数和边数
    vector<Edge> edges;   //边列表
    vector<int> G[M];     //每个结点出发的边编号(从0开始编号)
    vector<int> tree[M];
    bool done[N];         //是否已永久标号
    int d[N];             //s到各个点的距离
    int p[N];             //最短路中的上一条边
    ll L; 

    void init(int n, ll l) {
        this->n = n;
        for(int i = 0; i <= m * 2; i++) {
            G[i].clear();//清空邻接表
            tree[i].clear();
        }
        memset(p, -1, sizeof(p));
        edges.clear();//清空边表
        this->L = l;
    }  

    void addEdge(int from, int to, ll dist, int flag) {
        //如果是无向图,每条无向边需调用两次AddEdge
        edges.push_back((Edge){from, to, dist, flag});
        m = edges.size();
        G[from].push_back(m - 1);
    }  

    ll dijkstra(int s) {//求s到所有点的距离
        priority_queue<HeapNode> Q;
        for(int i = 0; i <= n; i++) d[i] = INF;
        d[s] = 0;
        memset(done, 0, sizeof(done));
        Q.push((HeapNode){0, s});
        while(!Q.empty()){
            HeapNode x = Q.top(); Q.pop();
            int u = x.u;
            if(done[u]) continue;
            done[u] = true;
            for(int i = 0; i < G[u].size(); i++){
                Edge& e = edges[G[u][i]];
                if(!e.flag) continue;
                if(d[e.to] > d[u] + e.dist){
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];
                    Q.push((HeapNode){d[e.to], e.to});
                }
            }
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            if (i == s) continue;
            if (d[i] == INF) ans += L;
            else ans += d[i];
        }
        return ans;
    }  

    void getTree(int s) {
        for (int i = 1; i <= n; i++)    {
            if (i == s || p[i] == -1) continue;
            tree[p[i]].push_back(s);
        }
    }

    void deleteEdge(int x) {
        edges[x].flag = 0;
        edges[x^1].flag = 0;
    }

    void recoverEdge(int x) {
        edges[x].flag = 1;
        edges[x^1].flag = 1;
    }
}dij;  

void input() {
    int u, v;
    ll dis;
    for (int i = 0; i < m; i++) {
        scanf("%d %d %lld", &u, &v, &dis);
        if (u == v) continue;
        dij.addEdge(u, v, dis, 1);
        dij.addEdge(v, u, dis, 1);
    }
}

void solve() {
    ll ans1 = 0, ans2, temp;
    for (int i = 1; i <= n; i++) {
        Dis[i] = dij.dijkstra(i);
        ans1 += Dis[i];
        dij.getTree(i);
    }
    ans2 = ans1;
    for (int i = 0; i < dij.edges.size(); i++) {
        dij.deleteEdge(i);
        if (i % 2 == 0) temp = ans1;
        for (int j = 0; j < dij.tree[i].size(); j++) {
            temp -= Dis[dij.tree[i][j]];
            temp += dij.dijkstra(dij.tree[i][j]);
        }
        dij.recoverEdge(i);
        ans2 = max(ans2, temp);
    }
    printf("%lld %lld\n", ans1, ans2);
}

int main() {
    while (scanf("%d %d %d", &n, &m, &l) == 3) {
        dij.init(n, l);
        input();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不可转载。

时间: 2024-08-26 11:50:07

uva 1416 Warfare And Logistics (最短路树)的相关文章

UVA 1416 - Warfare And Logistics(最短路树)

UVA 1416 - Warfare And Logistics 题目链接 题意:给定一个无向图,每个边一个正权,c等于两两点最短路长度之和,现在要求删除一边之后,新图的c值最大的是多少 思路:直接枚举删边,每次做一次dijkstra的话复杂度太高,其实如果建好最短路树,如果删去的边在最短路树上,才需要去做,这样复杂度就优化到(n^2mlog(n)),勉强可以接受 代码: #include <cstdio> #include <cstring> #include <vecto

UVA - 1416 Warfare And Logistics (最短路)

Description 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 sh

UVA 4080 Warfare And Logistics 战争与物流 (最短路树,变形)

题意:给一个无向图,n个点,m条边,可不连通,可重边,可多余边.两个问题,第一问:求任意点对之间最短距离之和.第二问:必须删除一条边,再求第一问,使得结果变得更大. 思路: 其实都是在求最短路的过程. 第一问可以floyd解决,也可以SSSP解决.注意是任意两个点,(a,b)和(b,a)是不同的,都要算. 第二问要穷举删除每条边,再求第一问.为了降低复杂度,假设用dijkstra求最短路,那么可以利用第一问中所生成的树,共n棵,每棵至多n-1条边,如果穷举的边不在该某树上,那么该树的所有路径长不

UVA 1416 最短路树

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

Warfare And Logistics UVALive - 4080 (最短路树)

Warfare And Logistics UVALive - 4080 题意:给n个点m条边.令c为每对节点的最短路长度之和.要求删除一条边后使得新的c值c'最大,不连通的两点对短路视为L. [如果每次删除一条边,要跑m次dijkstra,其实其中很多次都对最短路没有影响,因为删掉的边不在最短路里] [因此,可以每次删除最短路树中的一条边,需要跑n次,复杂度降低到可接受程度] 1 #include <bits/stdc++.h> 2 #define LL long long 3 using

Warfare And Logistics UVA - 1416

题目链接:https://vjudge.net/problem/UVA-1416 题解: 这是一个最短路的好题,首先我们考虑如果暴力弗洛伊德,显然时间复杂度不对,如果做n次spfa好像复杂度也不对,所以考虑优化这个暴力. 我们考虑对于一个单源最短路,只有改变了最短路树中的某条边,才需要重新做一次最短路.所以我们不需要对于每条边都重新做最短路,只需要对于在最短路数上的边做,所以时间复杂度就优化成了你] mn^2log(n). 实现的时候要用pre数组记下,以i为终点的最短路树的边,实现有点复杂,看

UVALive - 4080 Warfare And Logistics (SPFA+最短路树)

题目大意:有N个点,M条路,如果两条路不连通的话,就将这两条路的距离设置为L 现在要求你求出每两点之间的最短距离和 接着要求 求出炸断 给出的M条路中的一条路后,每两点之间的最短距离和的最大值 解题思路:这题跟HDU-2433类似,不过这题的权值是不一样的 但具体的思路是差不多的 先预处理出以每个点为源点的最短路树,并纪录每个点的pre和以每个点为源点的最短距离和,这样就可以求出每两点之间的最短距离和了 接着依次删边,如果删除的边不在该点最短路树上,那么就可以用预处理纪录的以该点为源点的最短距离

UVALive 4080 Warfare And Logistics(Dijkstra+最短路树)

 题意:给定一个n节点m条边的无向图,定义c为每对顶点的最短路之和,要求删掉一条边重新求一个c值c',求出c'最大值. 思路:如果用floyd算法计算c,每尝试删除一条边都要重新计算一次,时间复杂度为O(n*n*n*m),很难承受.如果用n次Dijkstra计算单源最短路,时间复杂度味O(n*m*m*logn).虽然看上去比之前的好,但由于佛洛依德算法的常数很小,实际运行时间差不多.这时候,可以考虑最短路树.因为在源点确定的情况下,只要最短路树不被破坏,起点到所有点的距离都不会发生改变.也就

la4080 Warfare And Logistics 罗列+最短

为了图.计算最短随机分ans1.和删除边缘.免费才能够获得最大和短路之间的最大分ans2,如果这两个不沟通.看作是两个点之间的最短距离l. 第一个想法是枚举每个边缘,然后运行n最短时间.但是,这种复杂性是1000*1000*100*log(100),太大了..事实上在固定起点,求出单元最短路的时候.同一时候能够求出单源最短路树,仅仅有删除的边在树上的时候.源点到任一点的最短路才会有变化,所以在每次跑单源最短路的时候,仅仅须要枚举树上的n-1条边就能够了.累加一下删除每一条边时,在当前源点的情况下