六度分离( floyd算法找最短路径 )

题目
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
web矩阵
第三步
动态改变矩阵。
我们把两个点之间有边的情况叫做有直接联系。当我们键入矩阵时,只键入了有直接联系的两个点之间的边长(虽然在这个例子中每个点都有直接联系),但我们知道,存在一种情况,即两个点没有直接联系但有间接联系,而这种情况我们在上一步不能体现。因此我们要完善这个网络。

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值