hdu4635(强连通)

链接:点击打开链接

题意:问一个有向图最多添加多少条边使得这个图仍不是强连通图,如果这个图已经是强连通图则直接输出-1

代码:

#include <vector>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int V,E;
vector<int> G[100005];
vector<int> rG[100005];
vector<int> vs;
bool used[100005];
int in[100005],out[100005];
int x[100005],y[100005],cmp[1000005],cnt[1000005];
void addedge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}
void dfs(int v){
    int i;
    used[v]=1;
    for(i=0;i<G[v].size();i++)
    if(!used[G[v][i]])
    dfs(G[v][i]);
    vs.push_back(v);
}
void rdfs(int v,int k){
    int i;
    used[v]=1;
    cmp[v]=k;
    for(i=0;i<rG[v].size();i++)
    if(!used[rG[v][i]])
    rdfs(rG[v][i],k);
}
int scc(){
    int i,k;
    memset(used,0,sizeof(used));
    vs.clear();
    for(i=0;i<V;i++)
    if(!used[i])
    dfs(i);
    memset(used,0,sizeof(used));
    k=0;
    for(i=vs.size()-1;i>=0;i--)
    if(!used[vs[i]])
    rdfs(vs[i],k++);
    return k;
}                                               //强连通模板
int main(){                                     //因为要使得最后图不是强连通,并且
    int t,i,j,ans,cas,tmp;                      //添加的边最多,因此最后图的强连通
    scanf("%d",&t);                             //分量应为2,并且两部分都是完全图,
    for(cas=1;cas<=t;cas++){                    //并且两部分之间可连接单向边
        scanf("%d%d",&V,&E);
        for(i=0;i<V;i++){                       //因为两部分都是完全图,因此问题变为
            G[i].clear();                       //V*(V-1)条边减去E后最少再减去多少条
            rG[i].clear();                      //也就是两个强连通分量可以连的单向边
            vs.clear();                         //的数量,有因为x+y和一定时,两个数
        }                                       //差距越大x*y越小,因此选择最小的x或y
        for(i=0;i<E;i++){                       //作为其中一个部分
        scanf("%d%d",&x[i],&y[i]);
        x[i]--,y[i]--;
        addedge(x[i],y[i]);
        }
        ans=scc();
        if(ans==1){                             //如果是强连通分量直接输出-1
            printf("Case %d: -1\n",cas);
            continue;
        }
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(cnt,0,sizeof(cnt));
        for(i=0;i<V;i++)                        //数出每个强连通分量中的点的个数
        cnt[cmp[i]]++;
        for(i=0;i<E;i++){   
            if(cmp[x[i]]!=cmp[y[i]]){           //记录每个强连通分量的入度和出度
                out[cmp[x[i]]]++;
                in[cmp[y[i]]]++;
            }
        }
        tmp=INF;
        for(i=0;i<V;i++)
        if(in[cmp[i]]==0||out[cmp[i]]==0)
        tmp=min(tmp,cnt[cmp[i]]);
        printf("Case %d: %d\n",cas,V*(V-1)-E-tmp*(V-tmp));
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值