Strongly connected HDU - 4635(tarjan+强连通分量)
題意:
給一個(gè)簡單有向圖,讓你加最多的邊,使他還是一個(gè)簡單有向圖。
題目:
Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected.
A simple directed graph is a directed graph having no multiple edges or graph loops.
A strongly connected digraph is a directed graph in which it is possible to reach any node starting from any other node by traversing edges in the direction(s) in which they point.
Input
The first line of date is an integer T, which is the number of the text cases.
Then T cases follow, each case starts of two numbers N and M, 1<=N<=100000, 1<=M<=100000, representing the number of nodes and the number of edges, then M lines follow. Each line contains two integers x and y, means that there is a edge from x to y.
Output
For each case, you should output the maximum number of the edges you can add.
If the original graph is strongly connected, just output -1.
Sample Input
3
3 3
1 2
2 3
3 1
3 3
1 2
2 3
1 3
6 6
1 2
2 3
3 1
4 5
5 6
6 4
Sample Output
Case 1: -1
Case 2: 1
Case 3: 15
分析:
1.首先要把這個(gè)圖變成一個(gè)完全圖,然后減去最初的m條邊。
2.因?yàn)橐蠹尤氲倪呑畲蠡?#xff0c;你需要強(qiáng)聯(lián)通縮點(diǎn),把入度為0或者出度為0的內(nèi)含節(jié)點(diǎn)最少的聯(lián)通塊找出來,然后再減去最小聯(lián)通塊內(nèi)的點(diǎn)與其他點(diǎn)的連接邊就可以了。(減去的最少,剩余的也越多)
3.考慮當(dāng)只有一個(gè)連通圖時(shí),不滿足,輸出-1;
AC代碼:
#include<stdio.h> #include<string.h> #include<vector> #include<iostream> #include<stack> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int M=1e5+10; int t,n,m,u,v,tot,k,mi,Case; vector<int>ve[M]; int dfn[M],low[M],co[M],out[M],in[M],num[M]; stack<int>st; void tarjan(int x) {dfn[x]=low[x]=++tot;st.push(x);//入棧for(int i=0; i<ve[x].size(); i++){int y=ve[x][i];if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if(!co[y])low[x]=min(low[x],dfn[y]);}if(low[x]==dfn[x])///某個(gè)節(jié)點(diǎn)回溯之后的low【u】值還是==dfn【u】的值,那么這個(gè)節(jié)點(diǎn)無疑就是一個(gè)關(guān)鍵節(jié)點(diǎn)(為強(qiáng)連通分量的一個(gè)頂點(diǎn)。){k++;/**縮點(diǎn),將連通分量縮成一個(gè)點(diǎn),建入新樹中*/while(1){int a=st.top();st.pop();co[a]=k;/*看做建了一個(gè)新樹,只有用強(qiáng)連通分量的頂點(diǎn)建入樹中*/num[k]++;/*記錄某連通分量內(nèi)有多少個(gè)點(diǎn)*/if(a==x)//(遍歷該連通分量內(nèi)有多少個(gè)點(diǎn)【在a前的點(diǎn),均為一個(gè)連通分量】)break;}} } int main() {scanf("%d",&t);Case=0;while(t--){tot=k=0;/**初始化*/memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(co,0,sizeof(co));memset(in,0,sizeof(in));memset(out,0,sizeof(out));memset(num,0,sizeof(num));scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)ve[i].clear();for(int i=0; i<m; i++){scanf("%d%d",&u,&v);ve[u].push_back(v);}for(int i=1; i<=n; i++)if(!dfn[i])tarjan(i);mi=inf;for(int i=1; i<=n; i++)for(int j=0; j<ve[i].size(); j++)if(co[i]!=co[ve[i][j]])out[co[i]]++,in[co[ve[i][j]]]++;for(int i=1; i<=k; i++)if(!in[i]||!out[i])mi=min(mi,num[i]);printf("Case %d: ",++Case);if(k==1)printf("-1\n");elseprintf("%d\n",n*(n-1)-m-mi*(n-mi));}return 0; } /**想法一: 找出強(qiáng)聯(lián)通塊,計(jì)算每個(gè)連通塊內(nèi)的點(diǎn)數(shù)。將點(diǎn)數(shù)最少的那個(gè)連通塊單獨(dú)拿出來, 其余的連通塊合并成一個(gè)連通分量。 那么假設(shè)第一個(gè)連通塊的 點(diǎn)數(shù)是 x 第二個(gè)連通塊的點(diǎn)數(shù)是 y 一個(gè)【強(qiáng)】連通圖最多(每兩個(gè)點(diǎn)之間,至少存在一條課互相到達(dá)的路徑)的邊數(shù)為n*(n-1) 一個(gè)連通圖的邊數(shù)至少為n*(n-1)- x*y + 1 則非連通圖最多的邊數(shù)為n*(n-1)- x*y 即 x*(x-1)+ y*(y-1)+ x*y 因?yàn)樵瓐D中已經(jīng)有m條邊 所以最多加 x*(x-1)+ y*(y-1)+ x*y - m 條邊 這里最少點(diǎn)數(shù)的強(qiáng)聯(lián)通分量要滿足一個(gè)條件,就是出度或者入度為 0才行,不然是不滿足的。 二: 縮點(diǎn)后 這其實(shí)就相當(dāng)于一個(gè)完全圖至少減去多少條邊,使之變成非強(qiáng)連通圖 肯定減去連通分量里點(diǎn)最少的那個(gè)了*/備戰(zhàn)ing,題目分析簡略,見諒,轉(zhuǎn)載請(qǐng)注明出處。。。。。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Strongly connected HDU - 4635(tarjan+强连通分量)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 减肥刚开始快为什么
- 下一篇: G - 水陆距离 HihoCoder -