zoukankan      html  css  js  c++  java
  • HDU2433—Travel (BFS,最短路)

    Travel

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

    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

    Source

    2008 Asia Chengdu Regional Contest Online

    Recommend

    lcy   |   We have carefully selected several similar problems for you:  2429 2437 2430 2436 2435

     

    大意:

    给定一个图,N个节点,M条双向边。记i节点到其他节点的最短距离的和为Si,求Si(1<=i<=N)的和sum

    然后假设其中一个边被毁,求此时的sum

    思路:

    若使用那几个最短路算法,之后每假设一个边被毁,就需要全部重新计算一遍,时间复杂度很高

    注意到每个边的权值都为1,此时用BFS求最短路径的话会很方便

    而且,BFS可以很好地解决之后删边的问题:

    只要记录一下第一次每个节点的BFS树,之后再判断要删的点是否在树枝上即可

    两处优化:

    1.原图为非连通图,无论删哪条边,距离恒为INF

    2.有重边,删除其中一条对全图无影响(因此在记录图时,记录的是两点之间边的个数)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef struct Edge
    {
        int beg, end;
    } Edge;
    
    Edge edge[3001];
    int Sum[101] = {0};
    int Map[101][101];
    bool visited[101];
    int prec[101][101];     // prec[x][y],用来存储第一遍第x个节点的BFS树中y节点的上一个节点
    int N, M;
    
    int BFS(int k, bool is_preprocess = true)//第二个参数表示的是否是第一遍遍历所有节点
    {
        int dis[101] = {0}; //记录到根节点的距离
        memset(visited, false, sizeof(visited));
        queue<int> Q;
        visited[k] = true;
        Q.push(k);
        int cnt = 1;
        int Sum = 0;
        while (!Q.empty())
        {
            int i = Q.front(); Q.pop();
            for (int j = 1; j <= N; ++j)
            {
                if (!visited[j] && Map[i][j] > 0)
                {
                    visited[j] = true;
                    if (is_preprocess)
                        prec[k][j] = i; //记录前驱,只记录第一次遍历的BFS树的节点前驱,由于BFS时要对每个节点都进行一遍BFS所以需要记录n个BFS树
                    dis[j] = dis[i] + 1;   //记录到根节点的距离
                    Sum += dis[j];
                    ++cnt;              //记录一下BFS中的节点数目,最后判断是否能够到达所有节点(cnt==N)
                    Q.push(j);
                }
            }
        }
        return (cnt == N) ? Sum : -1;
    }
    
    int main()
    {
        int x, y, sum ;
        while (cin >> N >> M)
        {
            memset(Sum, 0, sizeof(Sum));
            memset(Map, 0, sizeof(Map));
            memset(prec, 0, sizeof(prec));
            int i = 1;
            for ( ; i <= M; ++i)
            {
                //建树
                cin >> x >> y;
                Map[x][y]++;
                Map[y][x]++;//这样记录路径的话,可以方便的记录重边
                edge[i].beg = x;
                edge[i].end = y;
            }
            sum = 0;
            i = 1;
            for (; i <= N; ++i)
            {
                Sum[i] = BFS(i);  //需要存储每个节点的BFS树的路径和
                if (Sum[i] == -1)
                    break;
                else
                    sum += Sum[i];
            }
            if (i <= N)      //优化:原图为非连通图,无论删哪条边,距离恒为INF
            {
                for (int i = 0; i < M; ++i)
                    puts("INF");
                continue;
            }
            for (int i = 1; i <= M; ++i)
            {
                int x = edge[i].beg;
                int y = edge[i].end;
                if (Map[x][y] > 1)           //优化:有重边,删除其中一条对全图无影响
                {
                    cout << sum << endl;
                }
                else                    //删的是割边(不可能有Map[][]==0,因为前边过滤了非连通图)
                {
                    int sum1 = 0, j = 1, s1;
                    for (; j <= N; ++j)//遍历全部顶点,蛮力法
                    {
                        if (prec[j][y] == x || prec[j][x] == y) //x-y在第j棵bfs树上,只能蛮力
                        {
                            Map[x][y] = Map[y][x] = 0;  //删边
    
                            s1 = BFS(j, false);
                            if (s1 == -1) //非连通,直接返回INF
                            {
                                Map[x][y] = Map[y][x] = 1;  //恢复边
                                break;                      //跳转到114行
                            }
                            sum1 += s1;
                            Map[x][y] = Map[y][x] = 1;  //恢复边
                        }
                        else
                        {
                            sum1 += Sum[j];
                        }
                    }
                    if (j <= N)
                    {
                        puts("INF");
                        //  continue;
                    }
                    else
                    {
                        cout << sum1 << endl;
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    JavaScript
    关于setInterval()你所不知道的地方
    JavaScript面向对象和原型函数
    GET和POST有什么区别?及为什么网上的多数答案都是错的
    10个最常见的 HTML5 面试题及答案
    Ajax我选择这样入门
    前端应当了解的Web缓存知识
    JavaScript
    Linux rhel7 下MySQL5.7.18详细安装文档
    思科交换机配置DHCP的四个方面
  • 原文地址:https://www.cnblogs.com/liuzhanshan/p/6535113.html
Copyright © 2011-2022 走看看