一道floyd------体重

问题描述
近日,信竞班有人在散布谣言,说老板体重超重 ,这有损老板在同学们心中的完美形象,让老板很是头疼。老板还了解到,散布该谣言的人号称自己拥有最合适的体重,体重值位于所有人的正中间,老板决心找出这个家伙。

信竞班有n名同学,编号1到n,已知每名同学的体重都不相同。老板想知道,哪个同学的体重位于正中间。也就是如果将n名同学按体重由轻到重排序后,该名同学位于第(n+1)/2名,这名同学一定是谣言散布者。

但是同学们都不肯准确告诉老板他的体重,老板只好在暗中收集信息。

例如:n=5时,老板搜集到了如下信息:

1号同学比2号同学轻

3号同学比4号同学轻  

1号同学比5号同学轻  

2号同学比4号同学轻  

根据上面的情报,虽然老板不能准确得出哪个同学具有中间体重,但他可以肯定4号和1号不可能具有中间体重,因为,1、2、3比4轻,而2、4、5比1重,所以他可以排除到这两名同学。

写一个程序统计出目前我们最多能排除掉多少个同学。也就是确定有多少个同学肯定不会是中间体重。

输入格式
第一行:两个整数n和m,其中n为奇数表示学生总数,m表示何老板搜集到的信息条数。

接下来的m行,每行两个整数x和y,表示x号同学比y号同学重。

输出格式
若干个整数,按从小到大的顺序输出不可能是中间重量的学生的编号。
若一个也找不出来,输出0。

样例输入 1
5 4
2 1
4 3
5 1
4 2

样例输出 1
1 4

样例输入 2
11 5
1 2
3 4
5 6
7 8
9 10

样例输出 2
0

样例输入 3
31 29
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 1
12 1
13 1
14 1
15 1
16 1
17 1
18 1
19 1
20 1
21 1
22 1
23 1
24 1
25 1
26 1
27 1
28 1
29 1
30 1

样例输出 3
1

提示

1<=n<=100

1<=m<=5000

——————————————————————————————————
解:

/*
对于任意一个人i,我们需要算出比他轻的总人数light[i]和比他重的总人数heavy[i]。
若能够确定比i轻或比i重的人数>=(n+1)/2 ,那么可以确定此人一定不是中间体重
怎样统计出比i轻和比i重的总人数呢? 
我们通过floyd就可以推导出任意两人之间的轻重关系 
*/
#include<iostream>
#include<cstdio>
using namespace std;
//zhong[x][y]为true,表示x比y重; qing[x][y]为true,表示x比y轻。 
bool zhong[100][100],qing[100][100]; 
int heavy[100],light[100];
//heavy[i]记录比i轻的同学个数; light[i]记录比重的同学个数。 
int main()
{
	//freopen("data10.in","r",stdin);
	//freopen("data10.out","w",stdout);
	
	int n,m,i,j,k,x,y,ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		zhong[x][y]=true;
		qing[y][x]=true;
	}
	//floyd
	for(k=1;k<=n;k++)
	  for(i=1;i<=n;i++)
	    for(j=1;j<=n;j++)
	    {
	       if(zhong[i][k] && zhong[k][j])zhong[i][j]=true;
	       if(qing[i][k] && qing[k][j])qing[i][j]=true;
	    }
	    
	for(i=1;i<=n;i++)
	  for(j=1;j<=n;j++)
	  {
	     if(zhong[i][j])heavy[i]++;
	     if(qing[i][j])light[i]++;
	  }
	bool flag=false;
	for(i=1;i<=n;i++)
	  if(heavy[i]>=(n+1)/2 || light[i]>=(n+1)/2)
	  {
	  	 flag=true;
	     cout<<i<<" ";
	  }
	if(flag==false)cout<<0;
	return 0;
}

本人代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,s,x,a[101]= {},c[101]= {};
bool b[101][101]= {},f,d[101][101]= {};
int main()
{
	cin>>n>>m;
	for(int i=1; i<=m; i++)
	{
		cin>>s>>x;
		if(b[s][x]==0)
		{
			b[s][x]=1;
			d[x][s]=1;
			a[s]++;
			c[x]++;
		}
		for(int i=1; i<=n; i++)
		{
			if(b[x][i]==1&&b[s][i]==0)
			{
				b[s][i]=1;
				a[s]++;
			}
			if(d[i][x]==1&&d[i][s]==0)
			{
				d[i][s]=1;
				c[i]++;
			}
		}
	}
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			for(int k=1; k<=n; k++)
			{
				if(b[i][j]==1&&b[j][k]==1&&b[i][k]==0)
				{
					b[i][k]=1;
					a[i]++;
				}
				if(d[j][i]==1&&d[i][k]==1&&d[j][k]==0)
				{
					d[j][k]=1;
					c[j]++;
				}
			}
		}
	}
	for(int i=1; i<=n; i++)
	{
		if(a[i]>n/2)
		{
			cout<<i<<" ";
			f=1;
		}
		if(c[i]>n/2)
		{
			cout<<i<<" ";
			f=1;
		}
	}
	if(f==0)
	{
		cout<<"0";
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值