hdu 4635 最多能加多少边使得图不变成强连通图

首先跑一遍tarjan 缩点无异议 缩完点后 若scc_cnt = 1 那么直接输出 -1 对于多个点的连通图来说 首先缩了点的那个点 里面的点是随便 连的 sum += sz[i] * (sz[i] - 1) 最后减去已连的就好了
再其次就是 缩完点之后的图 是树 因为树 是单向边 所以我们可以把 已经按照那个方向 那个点全都 连上 其次就是还有反向边 反向边一定要剩下至少一个点没有连反向边 并且是叶子节点 这样我们就能完全选完了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>

using namespace std;

const int N = 2e5 + 10,M = 1e6 + 10;
typedef long long ll;
int n,m;
int head[N],to[M * 2],last[M * 2],cnt;
void add(int a,int b){
    
    
    to[++cnt] = b;
    last[cnt] = head[a];
    head[a] = cnt;
}

int chu[N],ru[N];
int dfn[N],low[N],times,bridge[N],sum,scc_cnt;
int belong[N],flag[N],sta[N],top,sz[N];
void tarjan(int x){
    
    
    dfn[x] = low[x] = ++times;
    sta[++top] = x,flag[x] = 1;
    for(int i = head[x]; i != -1; i = last[i]){
    
    
        int j = to[i];
        if(!dfn[j]){
    
    
            tarjan(j);
            low[x] = min(low[x],low[j]);
            if(dfn[x] < low[j]){
    
    
                bridge[j] = 1;
                sum++;
            }
        }else if(flag[j]){
    
    
            low[x] = min(low[x],dfn[j]);
        }
    }

    if(dfn[x] == low[x]){
    
    
        ++scc_cnt;
        int y;
        do{
    
    
            y = sta[top--];
            belong[y] = scc_cnt;
            sz[scc_cnt]++;
            flag[y] = 0;
        }while(y != x);
    }
}

vector<int>v;

int main(){
    
    
    int n,m;
    int t;
    cin >> t;
    for(int _ = 1; _ <= t; _++){
    
    
        cin >>n>> m;
        v.clear();
        memset(head,-1,sizeof head);
        memset(dfn,0,sizeof dfn);
        memset(sz,0,sizeof sz);
        memset(chu,0,sizeof chu);
        memset(ru,0,sizeof ru);
        top = 0,times = 0,scc_cnt = 0;
        cnt = 1;
        sum = 0;
        for(int i = 1; i <= m; i++){
    
    
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }

        for(int i = 1; i <= n; i++){
    
    
            if(!dfn[i]){
    
    
                tarjan(i);
            }
        }

        printf("Case %d: ",_);
        if(scc_cnt == 1){
    
    
            printf("-1\n");
            continue;
        }

        ll sum = 0;
        for(int i = 1; i <= scc_cnt; i++){
    
    
            sum += 1ll * sz[i] * (n - sz[i]);
        }
        sum /= 2;
        sum -= m;

        for(int i = 1; i <= scc_cnt; i++){
    
    
            sum += 1ll * sz[i] * (sz[i] - 1);
        }

        for(int i = 1; i <= n; i++){
    
    
            for(int j = head[i]; j != -1; j = last[j]){
    
    
                int k = to[j];
                if(belong[i] != belong[k]){
    
    
                    chu[belong[i]]++;
                    ru[belong[k]]++;
                }
            }
        }

        int minn = 0x3f3f3f3f,is;
        for(int i = 1; i <= scc_cnt; i++){
    
    
            if(ru[i] == 0 || chu[i] == 0){
    
    
                if(minn > sz[i]){
    
    
                    minn = sz[i];
                    is = i;
                }
            }
        }

        ll maxn = 0;
        for(int i = 1; i <= scc_cnt; i++){
    
    
            if(i == is) continue;
            maxn += 1ll * (n - sz[i] - minn) * sz[i];
        }

        cout << sum + maxn / 2  <<endl;

    }








    return 0;
}

猜你喜欢

转载自blog.csdn.net/qqqingyi/article/details/120642621
今日推荐