HDU-3836 tarjan縮點

HDU-3836

題目

在這裏插入圖片描述

題目大意

把這個圖變成強聯通圖需要加多少條邊

思路

tarjan縮點然後加邊,但是我不知道怎麼加,查了一下題解說是要每個點出入度>=1,一開始很不解爲什麼,後面發現這是單向條件,就是說雖然每個點出入度大於等於1的圖不一定是強連通圖,但是強聯通圖每個點出入度必是大於等於一的,因爲這樣纔可以保證每個點可以到達他(所以入度>=1,因爲要有一個入口),他可以達到所有點(所以出度>=1,因爲要有一個出口),最後特判只有一個scc的時候,其他情況就是出入度爲0數去max

代碼

#include <iostream>
#include <cstdio>
#include <set>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <string>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <fstream>
#include <iomanip>
#include <unordered_map>
using namespace std;
#define dbg(x) cerr << #x " = " << x << endl;
typedef pair<int, int> P;
typedef long long ll;
const int MAXN = 2e4 + 5;
const int MAXM = 5e4+5;
struct Edge
{
    int to ,next;
}edge[MAXM];
int head[MAXN], tot;
int Low[MAXN], DFN[MAXN], num[MAXN], Belong[MAXN];
int scc;
int Stack[MAXN];
bool Instack[MAXN];
int Index, top;
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = 1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!DFN[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])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = 0;
            num[scc]++;
            Belong[v] = scc;
        }while(u != v);
    }
}
void solve(int N)
{
    memset(DFN, 0, sizeof(DFN));
    memset(Instack, 0, sizeof(Instack));
    memset(num, 0, sizeof(num));
    Index = scc = top = 0;
    for(int i = 1; i <= N; i++)
    {
        if(!DFN[i]) tarjan(i);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    while(scanf("%d%d", &n ,&m) == 2)
    {
        init();
        vector<P> s;
        for(int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            addedge(u, v);
            s.push_back(P(u, v));
        }
        solve(n);
        int ans = 0;
        int In[MAXN] = {0}, Out[MAXN] = {0};
        for(int i = 0; i < s.size(); i++)
        {
            int u = s[i].first;
            int v = s[i].second;
            if(Belong[u] != Belong[v]) 
            {
                Out[Belong[u]]++;
                In[Belong[v]]++;
            }
        }
        int ans1 = 0, ans2 = 0;
        for(int i = 1; i <= scc; i++)
        {
            if(!In[i]) ans1++;
            if(!Out[i]) ans2++;
        }
        if(scc == 1) cout << 0 << endl;
        else cout << max(ans1, ans2) << endl;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章