zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    ATM代码及遇到的问题总结
    暑假日报-52
    暑假日报-51
    暑假日报-50
    暑假日报-49
    暑假日报-48
    线段树优化建图(炸弹 + 选课)
    联考day2 C. 舟游
    联赛模拟测试5题解
    第19周作业
  • 原文地址:https://www.cnblogs.com/Draymonder/p/7500338.html
Copyright © 2011-2022 走看看