• 中南OJ 2012年8月月赛 B题 Barricade


      中南大学OJ 2012年8月月赛,B题,Barricade题目链接)。

    Problem B: Barricade

    Description

      GBQC国一共有N个城市,标号分别为1, 2, …, N。N个城市间一共有M条单向通行的道路。

      不幸的是,GBQC国的城市1连续暴雨,使得整个城市淹没在汪洋洪水中,于是GBQC国领导人小明决定让城市1的居民暂时移居到城市N,于是一场浩浩荡荡的搬迁运动开始了。

      但还有一个问题需要解决,居民从城市1出发,如果走到某个城市时面对多条道路,那么城市1的居民就不知道该往哪个方向走了。

      为了解决上述问题,GBQC国领导人决定在一些道路的入口处设置“禁止通行”的路障,以确保城市1的居民从城市1出发,途径每个城市时,都有且仅有一条路可供选择,这样城市1的居民就能顺利搬迁到城市N了。

      现在GBQC国领导人想知道最少需要设置几个路障呢?

    Input

      输入包含多组测试数据。

      对于每组测试数据,第一行包含两个整数N (2 ≤ N ≤ 104), M(0 ≤ M ≤ 105),其中N、M的含义同上。接下来一共有M行,每行有三个整数x(1 ≤ x ≤ N)、y(1 ≤ y ≤ N),表示GBQC国有一条由城市x进入通向城市y的单向道路。

    Output

      对于每组测试数据,用一行输出一个整数表示最少需要设置几个路障。如果没办法从城市1出发走到城市N,则输出“-1”(不包括引号)。

    Sample Input

    3 4
    1 1
    1 2
    1 3
    1 3

    3 2
    1 3
    3 2

    2 0

    Sample Output

    3
    0
    -1

    Hint

      由于数据量较大,推荐使用scanf和printf。

      算法:广度优先搜索(BFS)。如果有n个岔路,必然要设置n-1个路障。累计路障的总个数。用打擂的方法,比出每个城市的路障累计数的最小值。如果终点没有累计,输出-1,否则,输出终点的路障累计数。

      C++语言源代码如下:

    #include <cstdio>
    #include <cstdlib>
    #include <map>
    #include <queue>
    
    using namespace std;
    
    typedef int COUNT;
    
    #define MAX_ROADS 100000
    
    void read_roads( multimap <int,int> & road, const int roads )
    {
        int start, end;
        for ( COUNT i = 0 ; i < roads ; i ++ )
        {
            // 读取路线的起点和终点
            scanf( "%d%d", &start, &end );
    
            // 把整条路作成pair,插入到road这个multimap中
            road.insert(make_pair<int,int>(start, end));
        }
    }
    
    void find_ways ( const int cities, const multimap <int,int> & road )
    {
        int current_city = 1; // 当前城市编号
        int current_blocks_count = 0; // 到达当前城市累计路障个数
        int next_city, next_blocks_count; // 下个城市编号及累计路障
    
        queue <int> city;  // queue是STL队列
        map <int, int> city_and_blocks_count; // 建立城市和路障累计数映射
    
        // 1号城市入队
        city.push( current_city ); // STL队列入队
    
        // 到达1号城市经历路障总和为零
        city_and_blocks_count.insert( make_pair<int, int>(current_city, current_blocks_count) );
    
        // 广度优先搜索(BFS)
        while ( !city.empty() ) // 当队列不为空时
        {
            current_city = city.front(); // STL队列,取得队头元素
            city.pop();  // STL队列的出队
    
            // 读取当前城市可以通往的城市的个数
            current_blocks_count = city_and_blocks_count[current_city];
    
            // 下一个城市路障累计数目,等于当前城市路障累计数目,加上
            // 通往下一个城市的个数减去一(减去的一就是要走的那条路)
            next_blocks_count = current_blocks_count + road.count(current_city) - 1;
    
            // 遍历所有可能的“下一个城市”
            for ( multimap <int,int>::const_iterator it = road.lower_bound(current_city) ;
                    it != road.upper_bound(current_city); it ++ )
            {
                next_city = (it->second);
                // 如果这个城市已经遍历过
                if ( city_and_blocks_count.count(next_city) > 0 )
                {
                    // 判断走当前的路会不会比以往的路路障更少,若更少则刷新记录
                    if ( city_and_blocks_count[next_city] > next_blocks_count )
                    {
                        // 下个城市入队
                        city.push( next_city );
                        // 刷新该城市的路障累计数
                        city_and_blocks_count[next_city] = next_blocks_count;
                    }
                }
                else  // 这个城市未遍历过
                {
                    city.push( next_city );  // 城市入队
    
                    // 插入该城市和路障累计数的映射
                    city_and_blocks_count.insert( make_pair<int, int>( next_city, next_blocks_count ) );
                }
            }
        }
    
        // 判断是否遍历过终点
        if ( city_and_blocks_count.count(cities) > 0 )
        {
            // 若遍历过终点,则输出路障累计数
            printf( "%d\n", city_and_blocks_count[cities] );
        }
        else
        {
            // 未到过终点,输出-1
            printf( "-1\n" );
        }
    }
    
    void test_case( const int cities, const int roads )
    {
        multimap <int,int> road;
    
        // 自己编写的读取道路数据
        read_roads( road, roads );
    
        // 自己编写的找路线函数
        find_ways( cities, road );
    }
    
    int main (void)
    {
        int cities, roads;
        while ( scanf( "%d%d", &cities, &roads ) != EOF )
        {
            test_case( cities, roads );
        }
        return EXIT_SUCCESS;
    }
  • 相关阅读:
    virtualbox+vagrant学习-2(command cli)-19-vagrant box命令
    virtualbox+vagrant学习-2(command cli)-24-Aliases别名
    virtualbox+vagrant学习-2(command cli)-23-vagrant version命令
    virtualbox+vagrant学习-2(command cli)-22-vagrant validate命令
    如何快速学习一门技术或进入一个岗位
    EL表达式详解
    关于JSP乱码问题
    java mail使用qq邮箱发邮件的配置方法
    数据库命名规范
    java中的Serializable接口的作用
  • 原文地址:https://www.cnblogs.com/yejianfei/p/2635265.html
Copyright © 2020-2023  润新知