HDU3836 Equivalent Sets (Tarjan缩点+贪心)

题意:

给你一张有向图,问你最少加多少条边这张图强连通

思路:

缩点之后,如果不为1个点,答案为出度为0与入度为0的点的数量的最大值

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
//#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
#include<unordered_map>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) 

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 5e4+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

vector<int>g[maxn];
int f[maxn];
int color[maxn],dfn[maxn],low[maxn],stack[maxn],vis[maxn],cnt[maxn];
int in[maxn],out[maxn];
int top,n,m,sum,ans;
int deep = 0;
void tarjan(int u){
    dfn[u]=++deep;
    low[u]=deep;
    vis[u]=1;
    stack[++top]=u;
    int sz=g[u].size();
    for(int i=0;i<sz;i++){
        int v=g[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else{
            if(vis[v]){
                low[u]=min(low[u],low[v]);
            }
        }
    }
    if(dfn[u]==low[u]){
        color[u]=++sum;
        vis[u]=0;
        while(stack[top]!=u){
            color[stack[top]]=sum;
            vis[stack[top--]]=0;
        }
        top--;
    }
    return;
}
PI edge[maxn];
vector<int>v[maxn];
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
void dfs(int x, int fa){
    if(x!=fa){
        int t1 = find(x);
        int t2 = find(fa);
        f[t1]=t2;
    }
    if(v[x].size()==0&&x!=fa&&vis[x]==0){vis[x]=1;ans++;}
    for(int i = 0; i <(int)v[x].size(); i++){
        int y = v[x][i];
        dfs(y,fa);
    }
}
int main() {
    while(~scanf("%d %d", &n, &m)){
        deep=0;
        top=ans=sum=0;
        for(int i = 1; i <= n; i++){
            f[i]=i;
            color[i]=low[i]=dfn[i]=stack[i]=vis[i]=cnt[i]=0;
            g[i].clear();
            v[i].clear();in[i]=out[i]=0;
        }
        for(int i = 1; i <= m; i++){
            int x,y;
            scanf("%d %d", &x, &y);
            edge[i] = make_pair(x,y);
            g[x].pb(y);
        }
        for(int i = 1; i <= n; i++){
            if(!dfn[i])tarjan(i);
        }
        /*for(int i = 1; i <= n; i++){
            printf("--%d %d %d\n",i,color[i],low[i]);
        }*/
        //suo dian
        for(int i = 1; i <= n; i++)vis[i]=0;
        for(int i = 1; i <= m; i++){
            int x = edge[i].fst;
            int y = edge[i].sc;
            x = color[x];
            y = color[y];
            if(x!=y){
                v[x].pb(y);
                in[y]++;
                out[x]++;
            }
        }
        int In=0;
        int Ou=0;
        for(int i = 1; i <= sum; i++){
            if(in[i]==0)In++;
            if(out[i]==0)Ou++;
        }
        int ans = max(In,Ou);
        if(ans==1)ans--;
        printf("%d\n",ans);

    }
    return 0;
}
/*
4 3
1 2
2 3
4 3

4 3
1 2
2 3
3 4

8 6
1 2
1 3
1 5
3 4
3 6
6 7

6 5
1 2
2 3
3 1
3 5
1 4

2 2 
1 2 
2 1

3 3
1 2
2 3
1 3

7 6
1 2
2 3
1 3
4 5
4 6
4 7

4 5
1 2
1 3
1 4
2 3
3 4

4 5
1 2
1 3
1 4
2 3
4 3

3 1
1 2
 */

 

posted @ 2019-06-05 21:25  wrjlinkkkkkk  阅读(259)  评论(0编辑  收藏  举报