warshall算法求传递闭包c++_算法学习笔记(57): 传递闭包

之前在题解里看到“传递闭包”,一直以为是一种很高级的算法,后来上离散数学的时候学到了,发现其实蛮简单的。

从数学上来说,传递闭包是在集合

上求包含关系
的最小传递关系。从关系图的角度来说,就是如果原关系图上有
路径,则其传递闭包的关系图上就应有从
。通俗地讲,就是 确定每个点是否能到达其他每个点

而这,把Floyd最短路算法稍微改一下即可。设E是原来的关系矩阵,则可以这样写:

for (int k = 1; k <= n; ++k)
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (E[i][k] && E[k][j])
                E[i][j] = 1;

就是依次判断:仅经由1号点能不能从i到达j,仅经由1、2号点能不能从i到达j……最后得到的E是传递闭包的关系矩阵。 E[i][j]如果等于1,则表示存在从ij的路径。时间复杂度是


(POJ1975 Median Weight Bead)

Description
There are N beads which of the same shape and size, but with different weights. N is an odd number and the beads are labeled as 1, 2, ..., N. Your task is to find the bead whose weight is median (the ((N+1)/2)th among all beads). The following comparison has been performed on some pairs of beads:
A scale is given to compare the weights of beads. We can determine which one is heavier than the other between two beads. As the result, we now know that some beads are heavier than others. We are going to remove some beads which cannot have the medium weight.
For example, the following results show which bead is heavier after M comparisons where M=4 and N=5.
1. Bead 2 is heavier than Bead 1.
2. Bead 4 is heavier than Bead 3.
3. Bead 5 is heavier than Bead 1.
4. Bead 4 is heavier than Bead 2.
From the above results, though we cannot determine exactly which is the median bead, we know that Bead 1 and Bead 4 can never have the median weight: Beads 2, 4, 5 are heavier than Bead 1, and Beads 1, 2, 3 are lighter than Bead 4. Therefore, we can remove these two beads.
Write a program to count the number of beads which cannot have the median weight. Input
The first line of the input file contains a single integer t (1 <= t <= 11), the number of test cases, followed by the input data for each test case. The input for each test case will be as follows:
The first line of input data contains an integer N (1 <= N <= 99) denoting the number of beads, and M denoting the number of pairs of beads compared. In each of the next M lines, two numbers are given where the first bead is heavier than the second bead. Output
There should be one line per test case. Print the number of beads which can never have the medium weight. Sample Input
1
5 4
2 1
4 3
5 1
4 2 Sample Output
2

大意是给出一些水滴之间的的重量大小关系,求有多少滴水滴的重量不可能是这些水滴重量的中位数。(水滴的数量保证为奇数)

这就可以建个图(设

代表
号水滴的重量,则
有边代表
)求传递闭包,对每个点都统计
能到达多少个点、有多少个点能到达(相当于统计有多少水滴确定比它重、多少水滴确定比它轻)。如果这两个数中有一个大于 n/2,那它就不可能成为中位数。
#include <cstring>
#include <iostream>
using namespace std;
bool E[105][105];
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--)
    {
        int n, m;
        cin >> n >> m;
        memset(E, 0, sizeof(E));
        for (int i = 0; i < m; ++i)
        {
            int x, y;
            cin >> x >> y;
            E[x][y] = 1;
        }
        for (int k = 1; k <= n; ++k)
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= n; ++j)
                    if (E[i][k] && E[k][j])
                        E[i][j] = 1;
        int cnt = 0;
        for (int i = 1; i <= n; ++i)
        {
            int from = 0, to = 0;
            for (int j = 1; j <= n; ++j)
            {
                from += E[j][i];
                to += E[i][j];
            }
            cnt += from > n / 2 || to > n / 2;
        }
        cout << cnt << endl;
    }
    return 0;
}

POJ3660 Cow Contest

Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1.. N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.
The contest is conducted in several head-to-head rounds, each between two cows. If cow A has a greater skill level than cow B (1 ≤ AN; 1 ≤ BN; AB), then cow A will always beat cow B.
Farmer John is trying to rank the cows by skill level. Given a list the results of M (1 ≤ M ≤ 4,500) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory. Input
* Line 1: Two space-separated integers: N and M
* Lines 2.. M+1: Each line contains two space-separated integers that describe the competitors and results (the first integer, A, is the winner) of a single round of competition: A and B Output
* Line 1: A single integer representing the number of cows whose ranks can be determined Sample Input
5 5
4 3
4 2
3 2
1 2
2 5 Sample Output
2

有若干只牛,给出它们之间的一些胜负关系,试求有多少只牛的排名无法确定。

这个题我总感觉可以用并查集或拓扑排序之类的方法,但数据范围这么小,用传递闭包应该是最简单的了。求出传递闭包后,对于每个点,如果存在另一个点,既不能到达它也不能被它到达,说明这个点对应牛的排名是无法确定的。

#include <iostream>
using namespace std;
bool E[105][105];
int main()
{
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i)
    {
        int x, y;
        cin >> x >> y;
        E[x][y] = 1;
    }
    for (int k = 1; k <= n; ++k)
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                if (E[i][k] && E[k][j])
                    E[i][j] = 1;
    int cnt = 0;
    for (int i = 1; i <= n; ++i)
    {
        bool ok = true;
        for (int j = 1; j <= n; ++j)
            if (i != j && !E[i][j] && !E[j][i])
                ok = false;
        cnt += ok;
    }
    cout << cnt << endl;
    return 0;
}

Pecco:算法学习笔记(目录)​zhuanlan.zhihu.com
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值