hdu 2433 Travel(最短路径树+删边+bfs)

33 篇文章 0 订阅
13 篇文章 0 订阅

Travel

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1541    Accepted Submission(s): 522


Problem Description
      One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will always take the shortest way. There are M (M <= 3000) two-way roads connecting the towns, and the length of the road is 1.
      Let SUM be the total distance of the shortest paths between all pairs of the towns. Please write a program to calculate the new SUM after one of the M roads is destroyed.

 

Input
      The input contains several test cases.
      The first line contains two positive integers N, M. The following M lines each contains two integers u, v, meaning there is a two-way road between town u and v. The roads are numbered from 1 to M according to the order of the input.
      The input will be terminated by EOF.

 

Output
      Output M lines, the i-th line is the new SUM after the i-th road is destroyed. If the towns are not connected after the i-th road is destroyed, please output “INF” in the i-th line.
 

Sample Input
  
  
5 4 5 1 1 3 3 2 5 4 2 2 1 2 1 2
 

Sample Output
  
  
INF INF INF INF 2 2
 

题意:一个无向图,n个点,m条边。求依次删除各条边时,图中每对点的最短路径之和为多少,若图不连通,输出INF。
思路:先预处理,用bfs计算出未删边时每对点的最短路径之和,并生成每个点的最短路径树,即记录每个点到其他各个点的最短路径上经过了哪些边。删除一条边时,枚举每个点的最短路径树,若该树经过了要删的边,则重新计算出该点到其他各个点的最短路径之和,临时更新该点原先的最短路径之和。

AC代码:
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <algorithm>
#define ll __int64
#define L(rt) (rt<<1)
#define R(rt)  (rt<<1|1)

using namespace std;

const int INF = 1e7;
const int maxn = 105;
const int maxm = 3005;

int n, m, total;
int a[maxm], b[maxm], sum[maxn], cnt[maxn][maxn], dis[maxn];
bool used[maxn][maxn][maxn], vis[maxn];
void init()
{
    memset(cnt, 0, sizeof(cnt));
    memset(used, false, sizeof(used));
    memset(sum, 0, sizeof(sum));
}
int bfs(int s, int flag){
    queue<int> Q;
    for(int i = 1; i <= n; i++)
    {
        vis[i] = false;
        dis[i] = INF;
    }
    dis[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for(int v = 1; v <= n; v++)
        if(!vis[v] && (cnt[u][v] || cnt[v][u]))
        {
            vis[v] = true;
            if(flag) used[s][u][v] = used[s][v][u] = true;
            dis[v] = dis[u] + 1;
            Q.push(v);
        }
    }
    int ret = 0;
    for(int i = 1; i <= n; i++) ret += dis[i];
    return ret;
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        init();
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d", &a[i], &b[i]);
            cnt[a[i]][b[i]]++;          //记录重边
            cnt[b[i]][a[i]]++;
        }
        total = 0;
        bool flag = false;
        for(int i = 1; i <= n; i++)
        {
            sum[i] = bfs(i, 1);
            if(sum[i] >= INF)            //若图原本就不连通,那么删边后肯定不会连通
            {
                flag = true;
                break;
            }
            else total += sum[i];
        }
        for(int i = 0; i < m; i++)
        {
            if(flag)
            {
                printf("INF\n");
                continue;
            }
            int ans = total;
            cnt[a[i]][b[i]]--;
            cnt[b[i]][a[i]]--;
            if(cnt[a[i]][b[i]] > 0) printf("%d\n", total);
            else
            {
                bool con = true;
                for(int j = 1; j <= n; j++)
                    if(used[j][a[i]][b[i]])
                    {
                        ans -= sum[j];
                        int tmp = bfs(j, 0);
                        if(tmp >= INF)
                        {
                            con = false;
                            break;
                        }
                        else ans += tmp;
                    }
                if(!con) printf("INF\n");
                else printf("%d\n", ans);
            }
            cnt[a[i]][b[i]]++;
            cnt[b[i]][a[i]]++;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值