poj 3275 Ranking the Cows(floyd …

题目: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 用边表实现,学习了。。。


//11996K    219MS
#include <stdio.h>
#include <string.h>
#define M 1005

int mat[M][M],pre[M][M],suc[M][M]; //pre记录前驱,suc记录后继 pre[v][0],suc[u][0]代表v的前驱的个数
                                   //u的后继的个数
int main ()
{
    int n,m,i,j,k,u,v;
    while (~scanf ("%d%d",&n,&m))
    {
        int cnt = m;
        memset (mat,0,sizeof(mat));
        while (m --)
        {
            scanf("%d%d",&u,&v);
            mat[u][v] = 1;
            pre[v][++pre[v][0]] = u;   //v的前驱是u
            suc[u][++suc[u][0]] = v;   //u的后继是v
        }
        for (k = 1;k <= n;k ++)
            for (i = 1;i <= pre[k][0];i ++)
            {
                u = pre[k][i];              //k的前驱是u
                for (j = 1;j <= suc[k][0];j ++)
                {
                    v = suc[k][j];        //k的后继是v
                    if (!mat[u][v]) //u是k的前驱,v是k的后继 所以u是v的前驱
                    {
                        pre[v][++pre[v][0]] = u;     //u 和 v 之间也建立关系
                        suc[u][++suc[u][0]] = v;
                        mat[u][v] = 1;
                        cnt ++;
                    }
                }
            }
        printf ("%d\n",n*(n-1)/2 - cnt);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值