F - Islands---------------------------------思维(强连通分量+缩点)

F - Islands---------------------------------思维(强连通分量+缩点)_第1张图片

F - Islands---------------------------------思维(强连通分量+缩点)_第2张图片
题意:
给定n个点,m条有向边。问最少添加多少条边使得每个点都能到达其他点

解析:
求出强连通分量,然后找出入度为0的mx 和出度为0的mx1
输出max(mx,mx1)即可

注意强连通分量个数为1时,输出0

#include <bits/stdc++.h>

using namespace std;
const int N=4e5+1000;
int e[N<<1],ne[N<<1],h[N<<1],idx;
int dfn[N],low[N],cnt,scc;
int id[N],in[N],out[N];
int t,n,m;
bool st[N];
stack<int> q;
void add(int a,int b)
{
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    q.push(u);st[u]=true;
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j]){
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(st[j]){
            low[u]=min(low[u],dfn[j]);
        }
    }
    if(low[u]==dfn[u]){
        ++scc;
        int y;
        do{
            y=q.top();q.pop();
            id[y]=scc;
            //sz[scc]++;
            st[y]=false;
        }while(y!=u);
    }

}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        while(!q.empty()) q.pop();
        memset(st,false,sizeof st);
        memset(out,0,sizeof out);
        memset(in,0,sizeof in);
        memset(h,-1,sizeof h);
        memset(id,0,sizeof id);
        memset(dfn,0,sizeof dfn);
        memset(low,0,sizeof low);
        cnt=0;scc=0;idx=0;
        for(int i=1,x,y;i<=m;i++)
        {
            scanf("%d %d",&x,&y);
            add(x,y);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=h[i];~j;j=ne[j]){
                int v=e[j];
                int a=id[i];
                int b=id[v];
                if(a!=b){
                    out[a]++;
                    in[b]++;
                }
            }
        }
      //  cout<
        int mx=0,mx1=0;
        for(int i=1;i<=scc;i++)
        {

            if(in[i]==0) mx++;
            if(out[i]==0) mx1++;
        }
        mx=max(mx,mx1);
        if(scc==1) printf("0\n");
        else printf("%d\n",mx);
    }
    return 0;
}


你可能感兴趣的:(思维,图论)