POJ 3660 牛的排名 (Floyd 传递闭包)


题意: 

有n头牛, 给你m对关系(a, b)表示牛a能打败牛b, 求在给出的这些关系下, 能确定多少牛的排名。

思路:这题的难点就是,牛到达怎么样的状态,才能说他的排名是确定的。。。

仔细想想就是比牛强的人 + 比牛弱的人 == n-1  (自己不要考虑进去)

然后嘛解决此类办法是  传递闭包了!!!!


分析:

在这呢先说一下关系闭包:  

关系闭包有三种: 自反闭包(r), 对称闭包(s), 传递闭包(t)。

先画出 R 的关系图,再画出 r(R), s(R), t(R) 的关系图。

                      

我们今天用的是传递闭包。   仅作为个人理解 传递闭包: 关系之间具有传递性(例如a> b, b> c, 那么a> c), 在那些已给出的关系基础上, 通过传递性, 把所有可能的关系都找出来。  如上图。

 

这里需要先求一下所有牛之间的传递闭包, 那么我们这题与传递闭包又有什么关系呢。 下面将慢慢解答。 

如果一头牛被x头牛打败,并且可以打败y头牛,如果x+y=n-1,则我们容易知道这头牛的排名就被确定了,所以我们只要将任一头牛,可以打败其他的牛的个数x, 和能打败该牛的牛的个数y求出来,在遍历所有牛判断一下是否满足x+y=n-1,就知道这个牛的排名是否能确定了(而传递闭包,正好将所有能得出关系都求出来了), 再将满足这个条件的牛数目加起来就是所求解。 x可以看成是入度, y是出度。

 

在floyd-warshall(不了解该算法的点这里)求每对顶点间的最短路径算法中,可以通过O(v^3)的方法求出图的传递闭包。可以位每条边赋以权值1,然后运行Floyd-Wareshall。如果从  i  到  j  存在一条路径,则d(i,j)<N,否则d(i,j)=MAX。

 

 一种改进的算法是:由于我们需要的只是判断是否从i到j存在一条通路,所以在Floyd-Wareshall中的动态规划比较中,我们可以把min和+操作改为逻辑or( ||  )和逻辑(&&)也就是将  d[i][j] = min(d[i][j],  d[i][k]+dist[k][j]);    改成    if(d[i][j] == 1 || (d[i][k] == 1 && d[k][j] == 1))   d[i][j] = 1;

设  d(i,j) = 1表示从 i 到 j 存在一条通路 p,且 p 的所有中间节点都在0,1,2,...,k中, 否则d(i,j)=0。我们把边(i,j)加入到E*中当且仅当d(i,j)=1。



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 111;
int dp[N][N];
int main()
{
    int n,m,u,v,ans;
    int i,j,k;
    int c1,c2;
    cin>>n>>m;
    while(m--) {
        cin>>u>>v;
        dp[u][v]=1;
    }
    for(k=1;k<=n;k++) {
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                dp[i][j]=dp[i][j]||(dp[i][k] && dp[k][j]);
            }
        }
    }
    ans=0;
    for(i=1;i<=n;i++) {
        c1=c2=0;
        for(j=1;j<=n;j++) {
            if(i==j) continue;
            if(dp[i][j]) c1++;
            if(dp[j][i]) c2++;
        }
        if(c1+c2==n-1) ans++;
    }
    cout<<ans<<endl;
    return 0;
}










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值