奶牛排序问题

一 原问题描述

3275 -- Ranking the Cowsicon-default.png?t=M5H6http://poj.org/problem?id=3275

二 输入与输出

1 输入

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

2 输出

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

3 输入样例

5 5

2 1

1 5

2 3

1 4

3 4

4 输出样例

3

三 算法分析与设计

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

2 根据传递性,得到的7种关系,分别是

1>4

1>5

2>1

2>3

2>4

2>5

3>4

3 对于有 n 个节点的图,两两之间的关系一共有 n(n-1)/2 种,5个节点共有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(第1头牛产奶量大于第5头),则 p[1]=...100010

输入 1-4,让 p[1][4] = 1(第1头牛产奶量大于第4头),则 p[1]=...110010

输入 2-1,让 p[2][1] = 1(第2头牛产奶量大于第1头),则 p[2]=...000110

输入 2-3,让 p[2][3] = 1(第2头牛产奶量大于第3头),则 p[2]=...001110

输入 3-4,让 p[3][4] = 1(第3头牛产奶量大于第4头),则 p[3]=...011000

判断每个数组的每一位,存在如下逻辑

if(p[i][j]){
    p[i] = p[i]|p[j]; // 按位或运算,i 奶牛的产奶量大于 j 奶牛的产奶量,所以 j 奶牛和其他奶牛的产奶关系可以传递给 i,所以用或关系
}

例如:p[2][1]=1,则 p[2]=p[2]|p[1]=001110|110010=111110,奶牛2和奶牛1有关系,则奶牛1的关系传递给奶牛2。

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

四 代码

package graph;

import java.util.BitSet;
import java.util.Scanner;

public class POJ3275 {
    public static void main(String[] args) {
        int n, m;
        Scanner scanner = new Scanner(System.in);
        // n 头牛
        n = scanner.nextInt();
        // m 个关系
        m = scanner.nextInt();
        
        BitSet p[] = new BitSet[n + 1];
        for (int i = 1; i <= n; i++) {
            p[i] = new BitSet(n + 1);
        }

        for (int i = 1; i <= n; i++)
            p[i].set(i);
        while (m-- != 0) {
            int u, v;
            u = scanner.nextInt();
            v = scanner.nextInt();
            p[u].set(v);
        }
        for (int k = 1; k <= n; k++)
            for (int i = 1; i <= n; i++)
                if (p[i].get(k))
                    p[i].or(p[k]);
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (p[i].get(j)) {
                    ans++;
                }
            }
        }
        System.out.println(n * (n - 1) / 2 - ans + n);
    }
}

五 测试

绿色为输入,白色为输出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值