Ranking the Cows
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 }