hdu2767 Proving Equivalences有向图的强连通_Tarjan缩点

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4343    Accepted Submission(s): 1541

Problem Description

Consider the following exercise, found in a generic linear algebra textbook.

Let A be an n × n matrix. Prove that the following statements are equivalent:

1. A is invertible.
2. Ax = b has exactly one solution for every n × 1 matrix b.
3. Ax = b is consistent for every n × 1 matrix b.
4. Ax = 0 has only the trivial solution x = 0.

The typical way to solve such an exercise is to show a series of implications. For instance, one can proceed by showing that (a) implies (b), that (b) implies (c), that (c) implies (d), and finally that (d) implies (a). These four implications show that the four statements are equivalent.

Another way would be to show that (a) is equivalent to (b) (by proving that (a) implies (b) and that (b) implies (a)), that (b) is equivalent to (c), and that (c) is equivalent to (d). However, this way requires proving six implications, which is clearly a lot more work than just proving four implications!

I have been given some similar tasks, and have already started proving some implications. Now I wonder, how many more implications do I have to prove? Can you help me determine this?

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:

* One line containing two integers n (1 ≤ n ≤ 20000) and m (0 ≤ m ≤ 50000): the number of statements and the number of implications that have already been proved.
* m lines with two integers s1 and s2 (1 ≤ s1, s2 ≤ n and s1 ≠ s2) each, indicating that it has been proved that statement s1 implies statement s2.

Output

Per testcase:

* One line with the minimum number of additional implications that need to be proved in order to prove that all statements are equivalent.

Sample Input

2

4 0

3 2

1 2

1 3

Sample Output

4

2

#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
const int M = 50005;

struct edge {
    int v, next;
    edge() {}
    edge(int v, int next): v(v), next(next) {}
}e[M], e2[M];

int head[N], head2[N], num[N], in[N], out[N], tot, tot2;
int low[N], dfn[N], Stack[N], belong[N];
int scc, Index, top;
bool Instack[N];

void addedge(int u, int v, bool is) {
    if(is) {
        e[tot] = edge(v, head[u]);
        head[u] = tot++;
    }else {
        e2[tot2] = edge(v, head2[u]);
        head2[u] = tot2++;
    }
}

void Tarjan(int u) {
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for(int i = head[u]; ~i; i = e[i].next) {
        v = e[i].v;
        if(!dfn[v]) {
            Tarjan(v);
            if(low[u] > low[v]) low[u] = low[v];
        }else if(Instack[v] && low[u] > dfn[v]) {
            low[u] = dfn[v];
        }
    }

        if(low[u] == dfn[u])
        {
            scc++;
            do {
                v = Stack[--top];
                Instack[v] = false;
                belong[v] = scc;
                num[scc]++;
            } while(v != u);
        }
}

void solve(int n)
{
    memset(dfn, 0, sizeof dfn);
    memset(Instack, false, sizeof Instack);
    memset(num, 0, sizeof num);
    Index = scc = top = 0;
    for(int i = 1; i <= n; ++i) if(!dfn[i]) Tarjan(i);
}
void init() {
    tot = tot2 = 0;
    memset(head, -1, sizeof head);
    memset(head2, -1, sizeof head2);
}

int main()
{
    int _; scanf("%d", &_);
    while(_ --)
    {
        init();
        int n, m, u, v;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m ;++i) {
            scanf("%d%d", &u, &v);
            addedge(u, v, true);
        }
        solve(n);
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);

        for(int u = 1; u <= n; ++u) {
            for(int i = head[u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if(belong[u] != belong[v]) {
                    addedge(belong[u], belong[v], false);
                }
            }
        }
        for(int u = 1; u <= scc; ++u) {
            for(int i = head2[u]; ~i; i = e2[i].next) {
                int v = e2[i].v;
                in[v]++;
                out[u]++;
            }
        }
        int a = 0, b = 0;
        for(int i = 1; i <= scc; ++i) {
            if(in[i] == 0) a++;
            if(out[i] == 0) b++;
        }
        printf("%d\n", scc == 1 ? 0 : max(a, b));
    }
    return 0;
}

  

Source

NWERC 2008

时间: 2024-12-25 10:52:41

hdu2767 Proving Equivalences有向图的强连通_Tarjan缩点的相关文章

UVALive-4287 Proving Equivalences 有向图的强连通分量+缩点

题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导. 思路:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图.找出所有的强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG.设出度为0的大节点个数为b,入度为0的大节点个数为a,则答案就是max(a,b). 1 #include<iostream> 2 #include<string> 3 #include<algorithm&g

hdu2767 Proving Equivalences --- 强连通

给一个图,问至少加入?多少条有向边能够使图变成强连通的. 原图是有环的,缩点建图,在该DAG图上我们能够发现,要使该图变成强连通图必须连成环 而加入?最少的边连成环,就是把图上入度为0和出度为0的点连上,那么其它的点就都能够互相到达了 所以答案就是max(入度为0的点,出度为0的点) #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <

Proving Equivalences (hdu 2767 强联通缩点)

Proving Equivalences Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3743    Accepted Submission(s): 1374 Problem Description Consider the following exercise, found in a generic linear algebra

hdu2767 Proving Equivalences,有向图强联通,Kosaraju算法

点击打开链接 有向图强联通,Kosaraju算法 缩点后分别入度和出度为0的点的个数 answer = max(a, b); scc_cnt = 1; answer = 0 #include<cstdio> #include<algorithm> #include<vector> #include<cstring> #include<stack> using namespace std; const int maxn = 20000 + 10;

HDU2767 Proving Equivalences

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5742    Accepted Submission(s): 1973 Problem Description Consider the following exercise, found in a generic linear algebra textbook. Let A be an

hdu 2767 Proving Equivalences 强连通缩点

给出n个命题,m个推导,问最少增加多少条推导,可以使所有命题都能等价(两两都能互推) 既给出有向图,最少加多少边,使得原图变成强连通. 首先强连通缩点,对于新图,每个点都至少要有一条出去的边和一条进来的边(这样才能保证它能到任意点和任意点都能到它) 所以求出新图中入度为0的个数,和出度为0的个数,添加的边就是从出度为0的指向入度为0的.这样还会有一点剩余,剩余的就乱连就行了. 所以只要求出2者的最大值就OK. #include <iostream> #include<cstring>

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点) ACM 题目地址:HDU 2767 题意: 给定一张有向图,问最少添加几条边使得有向图成为一个强连通图. 分析: Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了. 我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点. 统计DAG入度和出度,然后计算头尾,最大的那个就是所求. 代码: /* * Author: illuz <iil

UVA 12167 - Proving Equivalences(强连通分量+缩点)

UVA 12167 - Proving Equivalences 题目链接 题意:给定一些已经存在的等价性证明,要求全部等价,需要在多最少几次证明 思路:先求出强连通分量,然后进行缩点,在缩点后的图上统计入度和出度为0结点的最大值,就是需要加的边数,注意如果整个图已经是强连通,就直接是答案 代码: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include

UVALIVE 4287 Proving Equivalences (强连通分量+缩点)

题意:给定一个图,问至少加入多少条边能够使这个图强连通. 思路:首先求出这个图的强连通分量.然后把每个强连通分量缩成一个点.那么这个图变成了一个DAG,求出全部点的入度和出度,由于强连通图中每个节点的入度和出度至少为1.那么我们求出入度为零的节点数量和出度为零的节点数量.答案取最大值,由于在一个DAG中加入这么多边一定能够使这个图强连通.注意当这个图本身强连通时要特判一下,答案为零. #include<cstdio> #include<cstring> #include<cm