POJ 3275 Ranking the Cows (floyd传递闭包)

Ranking the Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 2248 Accepted: 1045

Description

Each of Farmer John's N cows (1 ≤ N ≤ 1,000) produces milk at a different positive rate, and FJ would like to order his cows according to these rates from the fastest milk producer to the slowest.

FJ has already compared the milk output rate for M (1 ≤ M ≤ 10,000) pairs of cows. He wants to make a list of C additional pairs of cows such that, if he now compares those C pairs, he will definitely be able to deduce the correct ordering of all N cows. Please help him determine the minimum value of C for which such a list is possible.

Input

Line 1: Two space-separated integers:  N and  M 
Lines 2.. M+1: Two space-separated integers, respectively:  X and  Y. Both  X and  Y are in the range 1... N and describe a comparison where cow  X was ranked higher than cow  Y.

Output

Line 1: A single integer that is the minimum value of  C.

Sample Input

5 5
2 1
1 5
2 3
1 4
3 4

Sample Output

3

Hint

From the information in the 5 test results, Farmer John knows that since cow 2 > cow 1 > cow 5 and cow 2 > cow 3 > cow 4, cow 2 has the highest rank. However, he needs to know whether cow 1 > cow 3 to determine the cow with the second highest rank. Also, he will need one more question to determine the ordering between cow 4 and cow 5. After that, he will need to know if cow 5 > cow 3 if cow 1 has higher rank than cow 3. He will have to ask three questions in order to be sure he has the rankings: "Is cow 1 > cow 3? Is cow 4 > cow 5? Is cow 5 > cow 3?"

Source

 

 

题目:FJ想按照奶牛产奶的能力给她们排序。现在已知有N头奶牛(1 ≤ N ≤ 1,000)。FJ通过比较,已经知道了M(1 ≤ M ≤ 10,000)对相对关系。每一对关系表示为“X Y”,意指X的产奶能力强于Y。现在FJ想要知道,他至少还要调查多少对关系才能完成整个排序。

思路:如果排序可以确定了,潜台词就是任意两头牛之间的关系都可以确定了。N头奶牛一共有C(N, 2) = N * (N - 1) / 2对关系。由现在已知的关系如能确认K对关系,则要调查的次数就是C(N, 2) - K。

问题再思考一下就能发现,若u强于v,就连一条由u到v的有向路。两个节点之间有联系,就等价于这两个节点之间有一条有向路。这样就变成了任两点之间是否存在路径问题,用floyd传递闭包就可以了。

但最多有1,000头奶牛,时间复杂度为O(N^3)。肯定会超,思考一下就会发现,枚举中间节点K之后就开始枚举起点u和终点v,若u与K,或者 v与K之间根本就不联通,那么绝对无法松弛。所以说更高效的方式就是起点只检查能通向K的节点,终点只检查K能通向的节点,这样就会把复杂度大大降低,因为边最多只有10000条。floyd 用边表实现,学习了。。

 

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 const int N=1010;
 8 
 9 int map[N][N],pre[N][N],suc[N][N];  //pre记录前驱,suc记录后继 pre[v][0]代表v的前驱的个数,suc[u][0]代表u的后继的个数
10 
11 int main(){
12 
13     //freopen("input.txt","r",stdin);
14 
15     int n,m;
16     while(~scanf("%d%d",&n,&m)){
17         memset(map,0,sizeof(map));
18         memset(pre,0,sizeof(pre));
19         memset(suc,0,sizeof(suc));
20         int u,v;
21         int cnt=m;
22         while(m--){
23             scanf("%d%d",&u,&v);
24             map[u][v]=1;
25             pre[v][++pre[v][0]]=u;  //v的前驱是u
26             suc[u][++suc[u][0]]=v;  //u的后继是v
27         }
28         int i,j,k;
29         for(k=1;k<=n;k++)
30             for(i=1;i<=pre[k][0];i++){
31                 u=pre[k][i];         //k的前驱是u
32                 for(j=1;j<=suc[k][0];j++){
33                     v=suc[k][j];        //k的后继是v
34                     if(!map[u][v]){ //u是k的前驱,v是k的后继 所以u是v的前驱
35                         pre[v][++pre[v][0]]=u;   //u 和 v 之间也建立关系
36                         suc[u][++suc[u][0]]=v;
37                         map[u][v]=1;
38                         cnt++;
39                     }
40                 }
41             }
42         printf("%d\n",n*(n-1)/2-cnt);
43     }
44     return 0;
45 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值