题目
1967年,美国著名的社会学家斯坦利·米尔格兰姆提出了一个名为“小世界现象(small world phenomenon)”的著名假说,大意是说,任何2个素不相识的人中间最多只隔着6个人,即只用6个人就可以将他们联系在一起,因此他的理论也被称为“六度分离”理论(six degrees of separation)。虽然米尔格兰姆的理论屡屡应验,一直也有很多社会学家对其兴趣浓厚,但是在30多年的时间里,它从来就没有得到过严谨的证明,只是一种带有传奇色彩的假说而已。
Lele对这个理论相当有兴趣,于是,他在HDU里对N个人展开了调查。他已经得到了他们之间的相识关系,现在就请你帮他验证一下“六度分离”是否成立吧。*
Input
本题目包含多组测试,请处理到文件结束。
对于每组测试,第一行包含两个整数N,M(0<N<100,0<M<200),分别代表HDU里的人数(这些人分别编成0~N-1号),以及他们之间的关系。
接下来有M行,每行两个整数A,B(0<=A,B<N)表示HDU里编号为A和编号B的人互相认识。
除了这M组关系,其他任意两人之间均不相识。
Output
对于每组测试,如果数据符合“六度分离”理论就在一行里输出"Yes",否则输出"No"。
Sample Input
8 7
0 1
1 2
2 3
3 4
4 5
5 6
6 7
8 8
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 0
Sample Output
Yes
Yes
首先简单复习一下我在B站大学学习的Floyd算法。
以这个图为例,我们可以发现他有几个特征,有顶点,有边,边上有权值(可以简单理解为路径长度或者边长),两个点之间有一条或者两条有向边,当然也可以一条都没有。
那么问题来了,如何用Floyd算法求任意两个点之间的路径长度?
我们假设有N个点,编号从1到N;
第一步
建立一个N×N的矩阵,代表此图。(web[N][N])
- 为啥是N*N的矩阵?
拿人际关系举例,A,B俩人,他们之间的关系可能是,A单方面认识B(A指向B),B单方面认识A(B指向A),和AB互相认识(AB互指),AB互不认识(AB之间没有边)。
第二步
我们规定web[i][j]表示从点 i -> 点 j的路径长度,但是当 i 不指向 j 时,他们之间的距离为正无穷。按照图示来键入矩阵。在这里右列表示 i, 上列表示 j
第三步
动态改变矩阵。
我们把两个点之间有边的情况叫做有直接联系。当我们键入矩阵时,只键入了有直接联系的两个点之间的边长(虽然在这个例子中每个点都有直接联系),但我们知道,存在一种情况,即两个点没有直接联系但有间接联系,而这种情况我们在上一步不能体现。因此我们要完善这个网络。
即
if (web[i][j] > web[i][k] + web[k][j])
web[i][j] = web[i][k] + web[k][j]
- why?
如果我们要从i点走到j点,可以直接从i点到j点,也可以从i点到k点,再到j点。但是一定是从i点直接到j点的路最短。(当然这是从现实层面的角度考虑,在图中可能存在i到k到j的路径长度小于i到j的情况,但是这不妨碍我们求最短路径)。所以一旦出现web[i][j] > web[i][k] + web[k][j]的情况,就说明还没有找到最短路径。
通过这三步,就可以找到任意两个点的最短路径了。
当然,还可以通过一个存储中间点的数组来具体确定是那几条路径(太晚了要睡了以后再补)
这个方法的缺点是:在第三步动态改变矩阵时,用到了一个三重循环,所以时间复杂度为n^3,不适合大量计算。
复习完毕,over;
在这道题中,由于每行输入的两个人是互相认识的,所以这两个人之间有双向的路径,并且长度都为1。要判断是否符合六度分离理论,就是要判断是否存在任意两个人,他们之间的路径长度是否超过7(中间隔了超过6个人)。
代码:
#include<stdio.h>
#include<string.h>
#define N 105
int main(void)
{
int n,m,i,j,k,a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
int web[N][N];
int flag = 1;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
web[i][j]=N;
}
//memset(web,N,sizeof(web)); 这样写vj会WA 吐辽
while(m--)
{
scanf("%d%d",&a,&b);
web[a][b]=web[b][a]=1;
}
for(k=0;k<n;k++)
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(web[i][j] > web[i][k]+web[k][j])
web[i][j] = web[i][k]+web[k][j];
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
if(web[i][j] > 7)
{
flag = 0;
break;
}
if(flag == 0)
break;
}
if(flag == 1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}