hdu 3836 Equivalent Sets

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3836

给你N个点,M条边的有向图,让你求加最少的边,使得该图 成为强连通图

思路:

  找出所有强连通分量,若连通分量数为1,ans = 0;

  否则缩点,若要使缩点后的图为强连通图,每个点至少入度和出度都为1,而一条边提供一个入度和一个出度 :答案就是入度为0 和 出度为0 的分量数的最大值。

网赛现学的 tarjin+缩点 还行,不难 ,浪费了好多时间  这次要好好补题了

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
#define mem(a,b) memset(a,b,sizeof(a))
int n,m,ti,scc;
struct node
{
    int from,to,next;
}e[N];
int head[N],dfn[N],vis[N],low[N],in[N],out[N],col[N];
stack<int>s;
void init()
{
    while (!s.empty())
        s.pop();
    ti = 0; scc = 0;
    mem(head,-1);
    mem(dfn,0);
    mem(vis,0);
    mem(low,0);
    mem(in,0);
    mem(out,0);
    mem(col,0);
}

void tarjan(int u)
{
    vis[u] = 1;//在栈里面
    s.push(u);
    dfn[u] = low[u] = ++ti;//时间戳这里是++  不然容易出现 dfn[u] = 0 情况 这样子
    for(int i=head[u];i != -1;i = e[i].next)
    {
        int v = e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(vis[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(dfn[u] == low[u] )//关键点
    {
        int x;
        scc++;
        do{
            x = s.top();
            s.pop();
            vis[x] =0;
            col[x] = scc;//分类 强连通分量
        }while (x != u);
    }
}

int main()
{
    while (~scanf("%d %d",&n,&m) && n+m)
    {
        init();
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            e[i].from = x;
            e[i].to = y;
            e[i].next = head[x];
            head[x] = i;
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                tarjan(i);
        }
        //cout<< "scc"<<scc<<endl;
        for(int i=0;i<m;i++)
        {
            int u = e[i].from, v= e[i].to;
            if(col[u] != col[v])
            {
                in[col[v]] ++;
                out[col[u]]++;
            }
        }
        int ans1=0,ans2=0;
        for(int i=1;i<=scc;i++)
        {
            if(!in[i])
                ans1++;
            if(!out[i])
                ans2++;
            //cout<< in[i] <<" "<<out[i]<<endl;
        }
        if(scc == 1)//已经是连通图了
        {
            cout<< 0 <<endl;
            continue;
        }
        cout<< max (ans1,ans2)<<endl;
    }
}
原文地址:https://www.cnblogs.com/Draymonder/p/7500338.html