【HDU - 4635】Strongly connected(缩点,新图性质,建图,Tarjan求强连通分量)
題干:
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 4Sample Output
Case 1: -1 Case 2: 1 Case 3: 15解題報告:
? ? 這題首先縮點,因為這些點之間肯定是強連通的,我們為了不讓他是個強連通圖,就是要新圖不再是一個強連通分量就可以了。Tarjan處理完了之后得到每個集合的點數和一張新圖,我們不去建圖,只需要記錄入度和出度,這樣就得到了一張DAG圖。我們要想加的邊盡量多但是不讓他是一個強連通圖,那么就需要讓這個新圖的scc控制在2。也就是剛剛好不是個強連通,所以我們先假設連上了所有的邊,然后考慮哪些邊是不能加的。特就是將新圖分成兩個大集合,讓他們之間只有單向邊就可以了。也就是我們要找到一個大集合A和大集合B,元素個數假設分別為x和n-x,這樣要減去的邊數就是x*(n-x),要讓這個值盡量小,所以我們枚舉每一個小集合(要出度為0或者入度為0的小集合),求出以他為A大集合,需要減去的邊數,維護最小值就可以了。
至于為什么要出度為0或者入度為0的小集合呢?因為如果是中間的某個集合,那么也要去掉的是? 與當前DAG序列的所有入度為零的小集合 之間的那些連邊,所以那樣肯定減去的很多,而且可以直接歸屬在我們寫的這種算法中。
當然也可以不用減法,直接A*B + A*(A-1) + B*(B-1) - m
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; struct Edge {int to;int ne; } e[MAX]; int head[MAX],tot; int DFN[MAX],LOW[MAX],col[MAX],clk,index,scc,stk[MAX],vis[MAX]; ll cnt[MAX]; int n,m; int in[MAX],out[MAX]; void add(int u,int v) {e[++tot].to = v;e[tot].ne = head[u];head[u] = tot; } void Tarjan(int x) {DFN[x] = LOW[x] = ++clk;vis[x] = 1;stk[++index] = x;for(int i = head[x]; ~i; i = e[i].ne) {int v = e[i].to;if(!DFN[v]) {Tarjan(v);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]) LOW[x] = min(LOW[x],DFN[v]);}if(LOW[x] == DFN[x]) {scc++;while(1) {int tmp = stk[index];index--;vis[tmp] = 0;col[tmp] = scc;cnt[scc]++;if(tmp == x) break;}} } void init() {memset(head,-1,sizeof head);tot = 0;for(int i = 1; i<=n; i++) {DFN[i] = LOW[i] = cnt[i] = 0;in[i] = out[i] = 0;}clk = 0;index = 0;scc = 0; } int main() {int t,iCase=0;cin>>t;while(t--) {scanf("%d%d",&n,&m);init();for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b);}for(int i = 1; i<=n; i++) {if(!DFN[i]) Tarjan(i);}if(scc == 1) {printf("Case %d: -1\n",++iCase);continue;}for(int u = 1; u<=n; u++) {for(int i = head[u]; ~i; i = e[i].ne) {int v = e[i].to;if(col[u] != col[v]) {out[col[u]]++;in[col[v]]++;}}}ll minn = n;for(int i = 1; i<=scc; i++) {if(in[i] == 0 || out[i] == 0) {minn = min(minn,cnt[i]);}} ll ans = 1LL * n * (n-1) - m;//最多還能增加這些邊 printf("Case %d: %lld\n",++iCase,ans - minn * (n-minn) );}return 0 ; } /* 14:36 - 14:53 */?
總結
以上是生活随笔為你收集整理的【HDU - 4635】Strongly connected(缩点,新图性质,建图,Tarjan求强连通分量)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 申请信用卡学历可以乱填吗 信用卡申请资料
- 下一篇: 【HDU - 1561】The more