您的位置:首页 > 其它

BFS经典例题Isenbaev number

2016-05-17 00:36 489 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bfs 搜索 算法 Isenbaev