UvaLive 4287 Proving Equivalences 强连通缩点

原题链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2288

题意:

给你一个有向图,问你至少需要添加多少条边,使得整个图强连通。

题解:

就。。直接缩点,令缩点后入度为0的点有a个,出度为0的点有b个,答案就是max(a,b)

代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<stack>
#define MAX_N 20004
using namespace std;

vector<int> G[MAX_N];
int dfn[MAX_N],low[MAX_N],ind;
bool vis[MAX_N];
stack<int> st;
bool inStack[MAX_N];

int id[MAX_N],tot=0;
vector<int> newG[MAX_N];
vector<int> newrG[MAX_N];

int n,m;

void init() {
    for (int i = 0; i <= n; i++) {
        G[i].clear();
        newG[i].clear();
        newrG[i].clear();
    }
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    ind = tot = 0;
    memset(vis, 0, sizeof(vis));
    while (st.size())st.pop();
    memset(inStack, 0, sizeof(inStack));
    memset(id, 0, sizeof(id));
}

void Tarjan(int u) {
    dfn[u] = low[u] = ++ind;
    st.push(u);
    inStack[u] = 1;
    vis[u] = 1;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (!vis[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (inStack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        tot++;
        int t;
        do {
            t = st.top();
            st.pop();
            inStack[t] = 0;
            id[t] = tot;
        } while (t != u);
    }
}

int main() {
    int T;
    cin.sync_with_stdio(false);
    cin >> T;
    while (T--) {
        cin >> n >> m;
        int ans = 0;
        init();
        for (int i = 0; i < m; i++) {
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
        }
        for (int i = 1; i <= n; i++)
            if (!vis[i])Tarjan(i);
        for (int u = 1; u <= n; u++)
            for (int i = 0; i < G[u].size(); i++)
                if (id[u] != id[G[u][i]]) {
                    newG[id[u]].push_back(id[G[u][i]]);
                    newrG[id[G[u][i]]].push_back(id[u]);
                }
        if (tot == 1) {
            cout << 0 << endl;
            continue;
        }
        int a = 0, b = 0;
        for (int u = 1; u <= tot; u++) {
            if (newG[u].size() == 0)a++;
            if (newrG[u].size() == 0)b++;
        }
        cout << max(a, b) << endl;
    }
    return 0;
}
时间: 2024-10-31 16:21:21

UvaLive 4287 Proving Equivalences 强连通缩点的相关文章

UVALive - 4287 Proving Equivalences(强连通分量 + DAG)

题目大意:给出N个命题,要求你证明这N个命题的等价性 比如有4个命题a,b,c,d,我们证明a<->b, b<->c,c<->d,每次证明都是双向的,因此一共用了6次推导 如果换成证明a->b,b->c,c->d,d->a,每次证明都是单向的,而只需4次就可以证明所有命题的等价性 现在给出M个命题证明,问还需要证明几个,才可以保证N个命题等价 解题思路:命题的等价,就相当于证明点到点之间是互相连通. 所以,将所给的命题证明当成一条有向边,构建出一

hdu 2767 Proving Equivalences 强连通缩点

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

UVALive - 4287 Proving Equivalences (强连通分量)

链接 : http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10294 题意 :  告诉你n个等价的命题 和m个关系 比如 (u,v)代表u可以推导出v, 问至少需要补充多少条边. 用强连通缩点成一张DAG. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <

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

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

hdu2767 Proving Equivalences --- 强连通

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

hdu 2767 Proving Equivalences(强连通入门题)

1 /************************************************* 2 Proving Equivalences(hdu 2767) 3 强连通入门题 4 给个有向图,求至少加多少条边使得图是所有点都是强连通的 5 由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大 6 于1.先求所有所有强连通分量,把每个强连通分量看成一个点 7 在找每个点的出度和入度,最后还差的出度和入度的最大值就是 8 答案. 9 10 ************

UVALive Proving Equivalences (强连通分量,常规)

题意:给一个有向图,问添加几条边可以使其强连通. 思路: 按照大白书p322做.tarjan算法求强连通分量,然后缩点求各个强连通分量的出入度,答案是max(入度为0的缩点个数,出度为0的缩点个数). 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define pii pair<int,int> 4 using namespace std; 5 const int N=20000+5; 6 const int INF=0x

UVALive 4287 Proving Equivalence

用tarjan找强连通分量,在一个强连通分量点已经等价缩点以后形成一个DAG,计算入度为0的点数a, 出度为0的b,取其中大的一个.特判强连通分量数为1的情况. 看懂tarjan算法以后还是比较简单的 #include<bits/stdc++.h> using namespace std; const int maxn = 2e4+5; const int maxm = 5e4+5; int head[maxn],nxt[maxm],to[maxm],ecnt; void addEdge(in

hdu - 2667 Proving Equivalences(强连通)

http://acm.hdu.edu.cn/showproblem.php?pid=2767 求至少添加多少条边才能变成强连通分量.统计入度为0的点和出度为0的点,取最大值即可. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <algorithm> 7 #i