【POJ No. 3275】奶牛排序 Ranking the Cows

【POJ No. 3275】奶牛排序 Ranking the Cows

官方题目地址

在这里插入图片描述

【题意】

约翰想按照奶牛的产奶能力给它们排序。

已知有N (1≤N ≤1 000)头奶牛,而且知道这些奶牛的M (1≤M≤10 000)种关系,将每种关系都表示为“X Y ”,表示奶牛X 的产奶能力大于奶牛Y 。约翰想知道自己至少还要调查多少对关系才能完成整个排序。

【输入输出】

输入:

第1行包含两个整数N 和M 。第2…M +1行,每行都包含两个整数X 和Y 。X 和Y 都在1~N 范围内,表示奶牛X 的排名高于奶牛Y。

输出:

单行输出至少还要调查多少种关系才能完成整个排序。

【样例】

在这里插入图片描述

【思路分析】

在输入样例中,cow2 >cow1 >cow5 ,cow2 >cow3 >cow4 ,所以cow2 的排名最高。不过,约翰需要知道排名大于cow1 及cow3 的排名第二的牛,还需要通过一个问题来确定cow4 和cow5 的顺序。之后,他需要知道如果cow1 大于cow3 ,那么cow5 是否大于cow3 。他必须问三个问题才能确定排名:“cow1 >cow3 ?cow4 >cow5 ?”“cow5 >cow3?”。

【算法设计】

① 根据输入样例,创建一个有向图。

在这里插入图片描述

② 根据传递性,得到的已知关系有7种,分别是:1>4、1>5、2>1、2>3、2>4、2>5、3>4。

③ 对于有n 个节点的图,两两之间的关系一共有n (n -1)/2种,5个节点共有5×4/2=10种关系,还需要知道10-7=3种关系即可。

[如何得到已知关系]

利用bitset位运算,将每个节点都用一个bitset 表示。

bitset<maxn>p[maxn]; //maxn表示位数,p[] 表示二进制数组

初始化时,p [ i ][ i ]=1,即p [i ]的第i 位为1(从右侧数第0位、1位、2位)。

输入1-5,令p [1][5]=1,则p [1]=…….100010。
输入1-4,令p [1][4]=1,则p [1]=…….110010。
输入2-1,令p [2][1]=1,则p [2]=…….000110。
输入2-3,令p [2][3]=1,则p [2]=…….001110。
输入3-4,令p [3][4]=1,则p [3]=…….011000。

判断每个数组的每一位:

if(p[i][k]){
	p[i] |= p[k]; //按位或运算
}

例如,p [2][1]=1,则p [2]=p [2]|p [1]= 001110 | 110010=111110。如果2和1有关系,而1和4、5有关系,则通过或运算,可以得出2和4、5也有关系。

通过此方法,可以找到每个点和其他点的关系。用ans累计每个数组元素1的个数,因为初始化时自己到自己为1,所以ans多算了n 种关系,已知关系数应为ans-n ,用n (n -1)/2减去已知关系数即可。

for(int i = 1; i <= n ; i ++){
	ans += p[i].count(); //每个数组中元素1 的个数
}
cout << n * (n - 1) / 2 - ans + n << endl;

【算法实现】

#include<iostream>
#include<bitset>

using namespace std;

const int maxn = 1005;
bitset<maxn>p[maxn];

int main(){
	
	int n , m;
	
	cin >> n >> m;
	
	for(int i = 1 ; i <= n ; i ++){
		
		p[i][i] = 1;
	}
	while(m --){
		
		int u , v;
		cin >> u >> v;
		p[u][v] = 1;
	}
	
	for(int k = 1; k <= n ; k++){
		
		for(int i = 1 ; i <= n ; i ++){
			
			if(p[i][k]){
				p[i] |= p[k];	
			}
			
		}	
	}
	
	int ans = 0;
	for(int i = 1; i <= n ; i++){
		ans += p[i].count();
	}
	
	cout << n * (n - 1) / 2 - ans + n << endl;
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ding Jiaxiong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值