HDU ~ 2433 ~ Travel(最短路径树)

在这里插入图片描述

题意

多组测试数据,每组输入N,M,表示有N个点,M条边,SUM表示任意两点间的最短距离求和。让你求解,假设每一条边被破坏时新的SUM。
注意:边为双向边,且可能有重边

思路

记sum[i]表示以 i 为起点的最短路之和。
以每个点 i 为起点求一棵最短路径树,pre[i][j]表示第 i 棵树上到 j 点的那条边的编号。
如果删除的这条边,不在第 i 棵树上,那么对sum[i]没有影响,如果在第 i 棵树上,那么就对以 i 为起点的重新跑一次BFS。维护答案即可。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 5;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int from, to, dist;       //起点,终点,距离
    Edge(int u, int v, int w):from(u), to(v), dist(w) {}
};

struct Dijkstra
{
    int n, m;                 //结点数,边数(包括反向弧)
    vector<Edge> edges;       //边表。edges[e]和edges[e^1]互为反向弧
    vector<int> G[MAXN];      //邻接表,G[i][j]表示结点i的第j条边在edges数组中的序号
    int vis[MAXN];            //标记数组
    int d[MAXN];              //s到各个点的最短路
    int pre[MAXN][MAXN];            //pre[i][u]表示到第i棵最短路树u点的那条边

    void init(int n)
    {
        this->n = n;
        edges.clear();
        for (int i = 0; i <= n; i++) G[i].clear();
        memset(pre, -1, sizeof(pre));
    }

    void AddEdge(int from, int to, int dist)
    {
        edges.push_back(Edge(from, to, dist));
        m = edges.size();
        G[from].push_back(m - 1);
    }

    void BFS(int s, int *sum)
    {
        for (int i = 0; i <= n; i++) d[i] = INF, vis[i] = false;
        d[s] = 0; vis[s] = true;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty())
        {
            int u = Q.front(); Q.pop();
            for (auto i : G[u])
            {
                Edge e = edges[i];
                if (vis[e.to]) continue;
                vis[e.to] = true;
                d[e.to] = d[u] + e.dist;
                pre[s][e.to] = i/2;
                Q.push(e.to);
            }
        }
        sum[s] = 0;
        for (int i = 1; i <= n; i++) sum[s] += d[i];
        //for (int i = 1; i <= n; i++) printf("%d ", d[i]); cout << endl;
    }

    int BFS(int s, int no)
    {
        for (int i = 0; i <= n; i++) d[i] = INF, vis[i] = false;
        d[s] = 0; vis[s] = true;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty())
        {
            int u = Q.front(); Q.pop();
            for (auto i : G[u])
            {
                if (i/2 == no) continue;
                Edge e = edges[i];
                if (vis[e.to]) continue;
                vis[e.to] = true;
                d[e.to] = d[u] + e.dist;
                Q.push(e.to);
            }
        }
        int res = 0;
        for (int i = 1; i <= n; i++)
        {
            if (d[i] == INF) return INF;
            else res += d[i];
        }
        return res;
    }

}gao;

int n, m, sum[MAXN];
int main()
{
    while (~scanf("%d%d", &n, &m))
    {
        gao.init(n);
        for (int i = 0; i < m; i++)
        {
            int u, v; scanf("%d%d", &u, &v);
            gao.AddEdge(u, v, 1);
            gao.AddEdge(v, u, 1);
        }
        for (int i = 1; i <= n; i++) gao.BFS(i, sum);
        for (int no = 0; no < m; no++)
        {
            int ans = 0;
            int u = gao.edges[no*2].from, v = gao.edges[no*2].to;
            for (int i = 1; i <= n; i++)
            {
                if (gao.pre[i][u] == no || gao.pre[i][v] == no)
                {
                    int x = gao.BFS(i, no);
                    if (x == INF) { ans = INF; break; }
                    ans = ans + x;
                }
                else ans += sum[i];
            }
            if (ans != INF) printf("%d\n", ans);
            else printf("INF\n");
        }
    }
    return 0;
}
/*
5 4
5 1
1 3
3 2
5 4
2 2
1 2
1 2
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值