BFS经典例题Isenbaev number

29 篇文章 0 订阅
16 篇文章 0 订阅

BFS——宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一。
下面由一道经典例题来引出博主对于构造一个图以及在图中使用广度优先搜索的一些理解。

题目:

Vladislav Isenbaev is a two-time champion of Ural, vice champion of TopCoder Open 2009, and absolute champion of ACM ICPC 2009. In the time you will spend reading this problem statement Vladislav would have solved a problem. Maybe, even two…
Since Vladislav Isenbaev graduated from the Specialized Educational and Scientific Center at Ural State University, many of the former and present contestants at USU have known him for quite a few years. Some of them are proud to say that they either played in the same team with him or played in the same team with one of his teammates…
Let us define Isenbaev’s number as follows. This number for Vladislav himself is 0. For people who played in the same team with him, the number is 1. For people who weren’t his teammates but played in the same team with one or more of his teammates, the number is 2, and so on. Your task is to automate the process of calculating Isenbaev’s numbers so that each contestant at USU would know their proximity to the ACM ICPC champion.

Input
The first line contains the number of teams n (1 ≤ n ≤ 100). In each of the following n lines you are given the names of the three members of the corresponding team. The names are separated with a space. Each name is a nonempty line consisting of English letters, and its length is at most 20 symbols. The first letter of a name is capital and the other letters are lowercase.

Output
For each contestant mentioned in the input data output a line with their name and Isenbaev’s number. If the number is undefined, output “undefined” instead of it. The contestants must be ordered lexicographically.

Sample Input
7
Isenbaev Oparin Toropov
Ayzenshteyn Oparin Samsonov
Ayzenshteyn Chevdar Samsonov
Fominykh Isenbaev Oparin
Dublennykh Fominykh Ivankov
Burmistrov Dublennykh Kurpilyanskiy
Cormen Leiserson Rivest

Sample Output
Ayzenshteyn 2
Burmistrov 3
Chevdar 3
Cormen undefined
Dublennykh 2
Fominykh 1
Isenbaev 0
Ivankov 2
Kurpilyanskiy 3
Leiserson undefined
Oparin 1
Rivest undefined
Samsonov 2
Toropov 1

大概中文意思就是:
Isenbaev是国外的一个大牛。
现在有许多人要参加ACM ICPC。
一共有n个组,每组3个人。同组的3个人都是队友。
大家都想知道自己与大牛的最小距离是多少。
大牛与自己的最小距离当然是0。大牛的队友和大牛的最小距离是1。大牛的队友的队友和大牛的最小距离是2……以此类推。
如果实在和大牛没有关系的只好输出undefined了。
第一行读入n。表示有n个组。1 ≤ n ≤ 100
接下来n行,每行有3个名字,名字之间用空格隔开。每个名字的开头都是大写的。
每行输出一个名字,名字后面空格后输出数字a或者字符串undefined,a代表最小距离。
名字按字典序输出。

需要的知识点:bfs,图结构。

BFS一般是和图连在一起的知识点。所以首先要知道怎么构造一个图:构造一个图可以用两种不同的方法,一是邻接矩阵存储方法,
二是邻接链表存储方法。
这里我用的是邻接矩阵存储方法。
它的主要思想是:利用两个数组来存储一个图。
一个是一维数组,用来存放图中顶点的相关数据。如具体到这道题用的是distance[],相关数据就是每个顶点和Isenbaev的距离。即:v0的数据放在distance[0]里面,v1放在distance[1]里面,以此类推。
第二个是一个二维数组,用来表示图中顶点之间的相互关系,称为邻接矩阵。
它是一个bool型矩阵,如adj[][],当adj[i][j] == 1表示两个顶点vi和vj之间有连线。== 0则没有。
具体到这道题目,这道题有一个小难点就是输入的名字都是string,每个点不是int了,不好建图。还有如何将他们剔除掉相同的名字,并且字典排序。
解决思路:其实这些问题都可以用STL的map来解决。利用map将名字一一映射成int,而且map有自动查重功能,并且输入进去的已经是按照字典排序好了的。
有一个坑点是没有Isenbaev的情况。

所谓的BFS访问,即是一层一层访问下去。先访问level0、再访问level1、level2……访问对象可以是图、树等数据结构。
做BFS访问的主要工具是queue,通过push、front、pop的交替使用,来实现逐层访问。(深度搜索对应stack)。下面先放出bfs实现的核心代码:

  start = (*iter).second; 
  queue<int> Q;
  int temp = start;
  distance[temp] = 0, visited[temp] = 1;
  Q.push(temp);
  while (!Q.empty()) {
      temp = Q.front(), Q.pop();
      for (i = 0; i < total_num; ++i) {
          if (!visited[i] && link[temp][i]) {
              distance[i] = distance[temp] + 1;
              visited[i] = 1;
              Q.push(i);
          }
      }
  }

下面是解决问题的代码:

#include "iostream"
#include "map"
#include "queue"
#include "string"
using namespace std;
int main() {
    //利用link、distance数组来建立一个图
    bool link[100][100], visited[100];
    int distance[100], num_of_teams, i, j, total_num, count = 0, start;
    //先存储在string数组里
    string name[100][3];
    std::map<string, int> map;
    std::map<string, int>::iterator iter;
    //记得初始化= =
    for (i = 0; i < 100; i++)
        for (j = 0; j < 100; ++j)
            link[i][j] = 0;
    for (i = 0; i < 100; i++) visited[i] = 0;
    for (i = 0; i < 100; i++) distance[i] = 0;
    cin >> num_of_teams;
    for (i = 0; i < num_of_teams; ++i) {
        for (j = 0; j < 3; ++j) {
            cin >> name[i][j];
            //利用name数组在输入的时候就记住他们的小组关系
            map.insert(make_pair(name[i][j], 0));
        }
    }
    int num = 0;
    //一共有多少个不同的人
    total_num = map.size(); 
    //将不同的人分别编号
    for (iter = map.begin(); iter != map.end(); ++iter)
        (*iter).second = num++;      
    //一个一个组查找,并将他们连在一起,注意这里是无向图,利用visited数组来防止重复访问                       
    for (i = 0; i < num_of_teams; ++i) {
        int n1 = (*map.find(name[i][0])).second, 
        n2 = (*map.find(name[i][1])).second,
        n3 = (*map.find(name[i][2])).second;
        link[n1][n2] = link[n2][n1] = link[n1][n3] = link[n3][n1] =
        link[n2][n3] = link[n3][n2] = 1;
    }
    iter = map.find("Isenbaev");
    //处理没有Isenbaev的情况
    if (iter == map.end()) {                                        
        for (iter = map.begin(); iter != map.end(); ++iter)
            cout << (*iter).first << " undefined\n";
        return 0;
    }
    //下面是FBS核心代码
    start = (*iter).second;                                         
    queue<int> Q;
    int temp = start;
    distance[temp] = 0, visited[temp] = 1;
    Q.push(temp);
    while (!Q.empty()) {
        temp = Q.front(), Q.pop();
        for (i = 0; i < total_num; ++i) {
            if (!visited[i] && link[temp][i]) {
                distance[i] = distance[temp] + 1;
                visited[i] = 1;
                Q.push(i);
            }
        }
    }
    for (iter = map.begin(); iter != map.end(); ++iter) {
        if (distance[(*iter).second] == 0 && (*iter).first != "Isenbaev")
            cout << (*iter).first << " undefined\n";
        else
            cout << (*iter).first << " " << distance[(*iter).second] << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值