La 4080 Warfare and logistics Dijkstra

題目大意:
給定n個點,m條邊的無向圖, 定義c爲任意兩點間的最短路之和,

c=w(i,j)|iV,jV

求初始時的c與刪去任意一條邊後的c’的最大值。
分析:
對於最初始時的c, 我們可以通過每次計算以某個點爲源點的最短路徑,不難發現,每次計算後的距離和就是初始值c。
每一次進行刪邊操作時,就可以枚舉每一條邊進行決策:刪除或者不刪除,對於刪除的邊,如果它不在以某個點爲源點的Dijkstra樹上,那麼刪除它對於最短路徑的長度就不會造成影響,所以我們可以忽略它,直接利用上一次計算初始c值時的答案即可。這樣可以使時間複雜度變得可以令人接受。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 10;
const int inf = 0x7fffffff;

struct edge { int from, to, dist; };
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[maxn];
    bool done[maxn];
    int dis[maxn], pre[maxn];

    void init(int n) {
        this->n = n;
        for(int i=0; i<n; i++) G[i].clear();
        edges.clear();
    }
    void add_edge(int from, int to, int dist) {
        edges.push_back((edge){from, to, dist});
        m = edges.size();
        G[from].push_back(m-1);
    }
    //get the single-source shortest path from s
    void dijkstra(int s) {
        priority_queue<Heapnode> q;
        for(int i=0; i<n; i++) dis[i] = inf; dis[s] = 0;
        memset(done, false, 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<(int)G[u].size(); i++) {
                edge& e = edges[G[u][i]];
                if(e.dist > 0 && dis[e.to] > dis[u] + e.dist) {
                    dis[e.to] = dis[u] + e.dist;
                    pre[e.to] = G[u][i];
                    q.push((Heapnode){dis[e.to], e.to});
                }
            }
        }
    }
}Dij;
int n, m, L, u, v, w;
vector<int> gr[maxn][maxn];
bool used[maxn][maxn][maxn]; // in the shortest path from src, the edge u->v wheather or not used
int idx[maxn][maxn]; //the number in the Dij structure
int sum_single[maxn];

int compute_c() {
    int ans = 0;
    memset(used, false, sizeof(used));
    for(int src=0; src < n; src++) {
        Dij.dijkstra(src);
        sum_single[src] = 0;
        for(int i=0; i<n; i++) {
            if(i != src) {
                int fa = Dij.edges[Dij.pre[i]].from;
                used[src][i][fa] = used[src][fa][i] = 1;
            }sum_single[src] += Dij.dis[i] == inf ? L : Dij.dis[i];
        }ans += sum_single[src];
    }
    return ans;
}
int compute_newc(int a, int b) { 
    int ans = 0;
    for(int src=0; src < n; src++) {
        if(!used[src][a][b]) ans += sum_single[src];
        else {
            Dij.dijkstra(src);
            for(int i=0; i<n; i++) 
                ans += Dij.dis[i] == inf ? L : Dij.dis[i];
        }
    }
    return ans;
}
int main() {
#ifndef ONLINE_JUDGE 
    freopen("data.txt", "r", stdin);
    freopen("ans.txt", "w", stdout);
#endif
    while(scanf("%d%d%d", &n, &m, &L) == 3 && n) {
        Dij.init(n);
        for(int i=0; i<n; i++) 
            for(int j=0; j<n; j++) 
                gr[i][j].clear();
        for(int i=0; i<m; i++) {
            scanf("%d%d%d", &u, &v, &w); u--, v--;
            gr[u][v].push_back(w);
            gr[v][u].push_back(w);
        }
        for(int i=0; i<n; i++) 
            for(int j=i+1; j<n; j++) if(!gr[i][j].empty()) {
                sort(gr[i][j].begin(), gr[i][j].end());
                Dij.add_edge(i, j, gr[i][j][0]);
                idx[i][j] = Dij.m - 1;
                Dij.add_edge(j, i, gr[i][j][0]);
                idx[j][i] = Dij.m - 1;
            }
        int c = compute_c();
        int c1 = -1;

        for(int i=0; i<n; i++) 
            for(int j=i+1; j<n; j++) if(!gr[i][j].empty()) {
                int& e1 = Dij.edges[idx[i][j]].dist;
                int& e2 = Dij.edges[idx[j][i]].dist;
                if(gr[i][j].size() == 1) e1 = e2 = -1;
                else e1 = e2 = gr[i][j][1];
                c1 = max(c1, compute_newc(i, j));
                e1 = e2 = gr[i][j][0];
            }
        printf("%d %d\n", c, c1);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章