hdu4635 Strongly connected 【計算強連通分量+縮點+思想】
阿新 • • 發佈:2018-12-07
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=4635
題意:給一個有向圖,求最多新增幾條邊讓原圖還不是強連通;
思路:試想一下,如果是個強連通圖,那麼就只有一個強連通分量,所以根據題意讓圖不是強連通那麼至少有兩個強連通分量;
所以設兩個強連通分量(兩個圖)為X , Y;此時兩個圖內肯定是每個點都和其餘的點相連 (x*(x-1) y*(y-1) )
再讓兩個圖直通單向連線 (x*y),這是最多能有的邊數,所以最後的 ans= x*(x-1) + y*(y-1) +(x*y)-m,即 n*n-n-a*(n - a)-m;(a是該強連通分量的點數,m是剛原圖的變數,所以要減去)
此外還要注意判斷,在找圖X時,要判斷圖X的出度或者入度為0,否則圖是強連通;
#include<cstring> #include<string> #include<cstdio> #include<stdlib.h> #include<iostream> #include<algorithm> #include<math.h> #include<map> #include<vector> #include<stack> #define inf 0x3f3f3f3f #include<queue> #include<set> using namespace std; typedef long long ll; const int N=2e5+5; struct node { int v,ne; } edge[N]; int head[N],dfn[N],low[N]; int belong[N],sum[N];//belong 記錄縮點,sum 記錄一個強連通分量內點的個數 int vis[N];//標記是否在棧內 int in[N],out[N]; int top,e,cut,m,n; stack<int>sta; void init() { while(!sta.empty()) sta.pop(); memset(head,-1,sizeof(head)); e=0; } void add(int a,int b) { edge[e].v=b; edge[e].ne=head[a]; head[a]=e++; } void tarjan(int now,int pre) { vis[now]=1; low[now]=dfn[now]=++top; sta.push(now); bool flag=1; for(int i=head[now]; i!=-1; i=edge[i].ne) { int v=edge[i].v;//這裡不需要判斷if(v==pre) 暫時不知道為啥 知道的大佬可以說一下哦 if(!dfn[v]) { tarjan(v,now); low[now]=min(low[now],low[v]); } else if(vis[v]) low[now]=min(low[now],dfn[v]); } if(low[now]==dfn[now])//縮點 { int v,size=0; cut++; while(true) { size++; v=sta.top(); sta.pop(); belong[v]=cut; vis[v]=0; if(v==now) break; } sum[cut]=size; } } void solve() { memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(belong,0,sizeof(belong)); top=0; cut=0; for(int i=1; i<=n; i++) { if(!dfn[i]) tarjan(i,-1); } if(cut==1) { printf("-1\n"); return; } int res=0; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(int i=1; i<=n; i++)//求出入度 { for(int j=head[i]; j!=-1; j=edge[j].ne) { int v=edge[j].v; if(belong[i]!=belong[v]) { in[belong[v]]++; out[belong[i]]++; } } } for(int i=1; i<=cut; i++) { if(in[i]&&out[i]) continue; res=max(res,n*n-n-(n-sum[i])*sum[i]-m); } printf("%d\n",res); } int main() { int T,cas=0; scanf("%d",&T); while(T--) { init(); int a,b; scanf("%d %d",&n,&m); for(int i=1; i<=m; i++) { scanf("%d %d",&a,&b); add(a,b); } printf("Case %d: ",++cas); solve(); } return 0; }