试题 算法提高 Degrees of Separation
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
在我们联系日益紧密的世界里,人们推测每个人和其他人的分离度不超过六(六度分离)。在这个问题里,你需要写一个程序来找出人们的关系网络中最大的分离度。
对于任意两个人,他们的分离度是联系两个人需要经过的最小的关系数。对于一个关系网络,最大的分离度是网络中任意两人的分离度的最大值。如果一个网络中有两个人没有通过关系链连接起来,这个网络是不连通的。
如下图所示,一个网络可以用一些连接两个人的对称关系来描述。一条线段表示两个人之间有联系。网络A描述了一个分离度最大值为2的网络,网络B没有连通。
输入格式
输入包含多组描述关系网络的数据,对于每组数据,第一行有两个数P,表示网络中人的数目,和R,关系的对数。接下来一行是R个关系。每个关系用两个字符串表示,代表网络中有关系的两个人的名字。每个名字是不同的,并且中间没有空格。因为一个人可能和多个人有联系,一个名字可能在一组数据中出现多次。
最后以一行两个0表示结束。
输出格式
对于每个网络,输出网络中最大的分离度。如果这个网络是不连通的,输出DISCONNECTED。每一个网络输出后再输出一个回车。按照样例输出中的格式输出。
样例输入
4 4
Ashok Kiyoshi Ursala Chun Ursala Kiyoshi Kiyoshi Chun
4 2
Ashok Chun Ursala Kiyoshi
6 5
Bubba Cooter Ashok Kiyoshi Ursala Chun Ursala Kiyoshi Kiyoshi Chun
0 0
样例输出
Network 1: 2
Network 2: DISCONNECTED
Network 3: DISCONNECTED
数据规模和约定
30%的数据2<=P<=15
100%的数据2<=P<=50,R>=1
解题思路
这题考的是图论中两点之间的距离,只是这个边的权值都为1。有两个要点:
1.如何把字符串转换为结点
2.如何求最大分离度
解答1:利用STL中的map<string,int>,将一个字符串一一映射到int中。因为字符串会有重复,所以当一个字符串没有出现过的时候才给它分配一个int编号。之后,就可以用图论的方法解决了。
解答2:对每个结点进行Bfs,利用队列和dis[]数组(记录步数),这时会有两种情况:1 对一个结点bfs,没有访问完所有结点,显然这种情况图不连通,输出disconnected;2 一个结点成功Bfs所有结点,如果最"远"的一个结点的dis值比ans大,那么ans要更新。这样对所有结点Bfs完成以后,ans就是最大分离度了。
PS. 因为要用map,不得不用string,对于string类型的输入,强烈推荐使用Cin,而非scanf,因为编者在使用scanf对string输入的时候,出现了下面的情况,string在10的位置已经结束了,但是在11的位置竟然出现了字符a!!!不知道是为什么会这样,导致提交了好几次都未通过。
AC代码如下:
#include<stdio.h>
#include<iostream>
#include<queue>
#include<string>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int MAXN = 50 + 1;
vector<int> graph[MAXN]; //邻接表
int P, R;
bool vis[MAXN]; //记录结点是否访问
int dis[MAXN]; //到达结点的步数
map<string, int> People;
int ans = 0;
void Bfs(int u) { //标准的Bfs格式,因本题求最大分离度,略微复杂
memset(dis, 0, sizeof(dis));
memset(vis, 0, sizeof(vis));
queue<int> Q;
vis[u] = 1;
Q.push(u);
int num = 1; //记录访问的结点个数
while (!Q.empty()) {
int now = Q.front();
if (num == P && Q.size() == 1) //判断结点是否都访问过了,并且是最后一个结点
ans = max(ans, dis[now]);
Q.pop();
for (int i = 0; i < graph[now].size(); i++) {
int next = graph[now][i];
if (!vis[next]) {
vis[next] = 1;
dis[next] = dis[now] + 1; //步数加1
num++; //已访问的结点加1
Q.push(next);
}
}
}
}
int main() {
int ccase = 0;
while (scanf("%d%d", &P, &R) && P&&R) {
People.clear();
for (int i = 0; i < MAXN; i++)
graph[i].clear();
ccase++;
ans = 0;
int k = 1;
char c[20],d[20];
//string c, d;
for (int i = 0; i < R; i++) {
//cin >> c >> d;
scanf("%s%s",c,d);
if(!People[c]) //将string映射到int
People[c] = k++;
if(!People[d])
People[d] = k++;
graph[People[c]].push_back(People[d]);
graph[People[d]].push_back(People[c]);
}
for (int i = 1; i <= P; i++) {
Bfs(i);
}
if (ans == 0)
printf("Network %d: DISCONNECTED\n\n", ccase);
else
printf("Network %d: %d\n\n", ccase, ans);
}
return 0;
}