HDU 4635 Strongly connected

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4635

解题思路:

题目大意是你能最多能添加多少边,使的这个图不是强连通图。其临界条件是差一条边成强连通图。

可以把图分成两个强连通图,左边的一个强连通分量点个数为y,右边一个强连通分量的个数为x。

然后x的所有点都与y的所有点都有x->y连线,没有y-x的连线。这就是最终答案。

x+y=n

x×(x-1)+y×(y-1)+x×y-m

化简的 n×n-x×y-n-m,很明显只有|x-y|的绝对值越大,最终结果就越大。

最后我们用Tarjan算法,进行缩点后可能形成现在这样的图

很明显只有入度,或出度为零的点才能选做x,或y。

实现代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 const int MAXN=100010;
  8 
  9 struct Edge{
 10     int to,next;
 11 }edges[MAXN];
 12 
 13 int head[MAXN],tot;
 14 
 15 void init(){
 16     memset(head,-1,sizeof(head));
 17     tot=0;
 18 }
 19 
 20 void addEdge(int u,int v){
 21     edges[tot].to=v;
 22     edges[tot].next=head[u];
 23     head[u]=tot++;
 24 }
 25 
 26 int DFN[MAXN],LOW[MAXN],Stack[MAXN],NUM[MAXN],Belong[MAXN];
 27 bool Instack[MAXN];
 28 int scc,Index,top;
 29 
 30 void Tarjan(int u){
 31     DFN[u]=LOW[u]=++Index;
 32     Stack[top++]=u;
 33     Instack[u]=true;
 34 
 35     int v;
 36     for(int i=head[u];i!=-1;i=edges[i].next){
 37          v=edges[i].to;
 38 
 39         if(!DFN[v]){
 40             Tarjan(v);
 41             if(LOW[u]>LOW[v])
 42                 LOW[u]=LOW[v];
 43         }else if(Instack[v]&&LOW[u]>DFN[v]) LOW[u]=DFN[v];
 44     }
 45 
 46     if(LOW[u]==DFN[u]){
 47         scc++;
 48         do{
 49             v=Stack[--top];
 50             NUM[scc]++;
 51             Instack[v]=false;
 52             Belong[v]=scc;
 53         }while(v!=u);
 54     }
 55 }
 56 
 57 int in[MAXN],out[MAXN];
 58 void solve(long long n,long long m){
 59     memset(DFN,0,sizeof(DFN));
 60     memset(NUM,0,sizeof(NUM));
 61     memset(Instack,0,sizeof(Instack));
 62     top=Index=scc=0;
 63 
 64     for(int i=1;i<=n;i++)
 65         if(!DFN[i])
 66             Tarjan(i);
 67 
 68     if(scc==1){
 69         cout<<-1<<endl;
 70         return;
 71     }
 72 
 73     memset(in,0,sizeof(in));
 74     memset(out,0,sizeof(out));
 75 
 76     for(int i=1;i<=n;i++)
 77     for(int j=head[i];j!=-1;j=edges[j].next){
 78         int v=edges[j].to;
 79         if(Belong[i]!=Belong[v]){
 80             out[Belong[i]]++;
 81             in[Belong[v]]++;
 82         }
 83     }
 84 
 85     long long ans=0;
 86 
 87     for(int i=1;i<=scc;i++){
 88         if(in[i]==0||out[i]==0){
 89             ans=max(ans,(n*n-(n-NUM[i])*NUM[i]-n-m));
 90         }
 91     }
 92 
 93     //注意数据溢出的情况
 94 
 95     printf("%lld\n",ans);
 96 }
 97 
 98 
 99 int main(){
100     int T;
101     scanf("%d",&T);
102     for(int i=1;i<=T;i++){
103 
104         init();
105         int n,m;
106         scanf("%d%d",&n,&m);
107         for(int j=0;j<m;j++){
108             int u,v;
109             scanf("%d%d",&u,&v);
110             addEdge(u,v);
111         }
112         printf("Case %d: ",i);
113         solve(n,m);
114 
115     }
116 }

 

转载于:https://www.cnblogs.com/IKnowYou0/p/6539134.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值