POJ 3177 Redundant Paths(强连通分量)
题目链接:http://poj.org/problem?id=3177
题目大意是一个无向图给你n个点m条边,让你求出最少加多少条边 可以让任意两个点相通两条及以上的路线(每条路线点可以重复,但是每条路径上不能有重边),简单来说就是让你加最少的边使这个图变成一个双连通图。
首先用tarjan来缩点,可以得到一个新的无环图,要是只有一个强连通分量,那本身就是一个双连通图。要是多个强连通分量,那我们可以考虑缩点后度数为1的点(肯定是由这个点开始连新边最优),那我们假设数出度数为1的点的个数为cnt,可以画几个图观察可得答案就是(cnt + 1) / 2。但是这题有个问题就是要去掉重边(A B和B A不算重边),不然会wa...,所以我用了二维map来去重边。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <map> 6 using namespace std; 7 const int MAXN = 5005; 8 map <int , map<int , int> > mp; 9 struct data { 10 int next , to; 11 }edge[MAXN * 5]; 12 int head[MAXN] , low[MAXN] , dfn[MAXN] , st[MAXN] , block[MAXN] , du[MAXN]; 13 int top , ord , sccnum , cont; 14 bool instack[MAXN]; 15 16 void init() { 17 memset(head , -1 , sizeof(head)); 18 memset(instack , false , sizeof(instack)); 19 memset(low , 0 , sizeof(low)); 20 memset(dfn , 0 , sizeof(dfn)); 21 memset(du , 0 , sizeof(du)); 22 top = ord = sccnum = cont = 0; 23 } 24 25 void add(int u , int v) { 26 edge[cont].next = head[u]; 27 edge[cont].to = v; 28 head[u] = cont++; 29 } 30 31 void tarjan(int u , int par) { 32 low[u] = dfn[u] = ++ord; 33 st[++top] = u; 34 instack[u] = true; 35 for(int i = head[u] ; ~i ; i = edge[i].next) { 36 int v = edge[i].to; 37 if(v == par) 38 continue; 39 if(!dfn[v]) { 40 tarjan(v , u); 41 low[u] = min(low[u] , low[v]); 42 } 43 else if(instack[v]) { 44 low[u] = min(low[u] , dfn[v]); 45 } 46 } 47 if(low[u] == dfn[u]) { 48 int v; 49 sccnum++; 50 do { 51 v = st[top--]; 52 instack[v] = false; 53 block[v] = sccnum; 54 }while(u != v); 55 } 56 } 57 58 int main() 59 { 60 int n , m , u , v; 61 while(~scanf("%d %d" , &n , &m)) { 62 init(); 63 mp.clear(); 64 while(m--) { 65 scanf("%d %d" , &u , &v); 66 if(!mp[u][v]) { 67 add(u , v); 68 add(v , u); 69 mp[u][v]++; 70 } 71 } 72 tarjan(1 , -1); 73 for(int u = 1 ; u <= n ; u++) { 74 for(int i = head[u] ; ~i ; i = edge[i].next) { 75 int v = edge[i].to; 76 if(block[u] != block[v]) { 77 du[block[u]]++; 78 } 79 } 80 } 81 int res = 0; 82 for(int i = 1 ; i <= sccnum ; i++) { 83 if(du[i] == 1) 84 res++; 85 } 86 printf("%d\n" , (res + 1) / 2); 87 } 88 }