hdu2767强连通+缩点 如果让我说:我只能说,实力决定一切

题意:给你一个有向图,然后添边,让该图成为连通分量为1的连通图,需要添加的边数

思路:强连通+缩点,记录每个连通分量的入度和初度为0 的个数。找一个最大的值

 刚开始自己认为如果一个连通分量的入度为1,那么它的出度一定为0,这是极大的错误。

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<vector>
#include<stack>
#define maxn 10010
using namespace std;
stack<int>S;
vector<int>gra[2*maxn];
int T,n,m;
int dfn[2*maxn],low[2*maxn],vis[2*maxn],belong[2*maxn],ind[2*maxn],outd[2*maxn];
int sum;
int tem;
int MIN(int a,int b)
{
    return a>b?b:a;
}
void tarjan(int pox)
{
    vis[pox]=2;
    dfn[pox]=low[pox]=++sum;
    S.push(pox);
    for(int i=0; i<gra[pox].size(); i++)
    {
        int t=gra[pox][i];
        if(!dfn[t])
        {
            tarjan(t);
            low[pox]=MIN(low[pox],low[t]);
        }
        else if(vis[t]==2)
        {
            low[pox]=MIN(low[pox],dfn[t]);
        }
    }
    if(low[pox]==dfn[pox])
    {
        tem++;
        while(!S.empty())
        {
            int gh=S.top();
            S.pop();
            belong[gh]=tem;
            ind[gh]=0;
            outd[gh]=0;
            vis[gh]=1;
            if(gh==pox)
                break;
        }
    }
}
int main()
{
    int a,b;
    int inMax,outMax;
    while(scanf("%d",&T)!=EOF)
    {
        while(T--)
        {
            tem=sum=0;
            inMax=outMax=0;
            scanf("%d%d",&n,&m);
            memset(dfn,0,sizeof(dfn));
            memset(vis,0,sizeof(vis));
            memset(low,0,sizeof(low));
            for(int i=0; i<2*maxn; i++)
                gra[i].clear();
            while(!S.empty())
                S.pop();
            for(int i=0; i<m; i++)
            {
                scanf("%d%d",&a,&b);
                gra[a].push_back(b);
            }
            for(int i=1; i<=n; i++)
                if(!dfn[i])
                    tarjan(i);
            if(tem==1)
            {
                printf("0\n");
                continue;
            }
            for(int j=1; j<=n; j++)
                for(int i=0; i<gra[j].size(); i++) //记录每个节点的入度:
                {
                    if(belong[j]!=belong[gra[j][i]])
                    {
                        outd[belong[j]]++;
                         ind[belong[gra[j][i]]]++;
                    }

                }
        //    printf("tem=%d\n",tem);
            for(int i=1; i<=tem; i++)
            {
                if(!ind[i])
                  inMax++;
                if(!outd[i])
                  outMax++;
            }
            /*
                if(ind[i]==1)
                    inMax++;
                else
                    outMax++;
            */
            printf("%d\n",inMax>outMax?inMax:outMax);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值