对于我来说真是一道好题,一开始纠结为缩点跟求块,最后还是一个8字形的图no了我一下。
/* *State: HDU3394 328MS 2052K 1918 B C++ 题意描述: * 公园有n个景点,公园的管理员计划要建m条道路,并且安排一 * 些形成回路的参观路径,如果一条道路可以被多条回路共用, * 那么这条边是冲突边,如果不能形成环的路则为不需要的边, * 现在就是求无向图中冲突边和不需要边的条数 *解题思路: * 把图分为多个块,然后判断每个块里面的边数,如果块的边数 * 等于块的点数,那么该块只有一个环,如果块的边数大于块的 * 点数,那么这个块中有多个环,并且这个块中的每条边都是多 * 个环里面的一部分。 * * *问题困惑:在一个没有连通分量的无向图中,带环的块一定是由一个只 * 有两个点的块相连着的,对不对?第一次求块,缩过点,求过 * 桥跟割边,但是想不到求块居然会遇到这么多麻烦,不过原因 * 就是求块的过程中,遇到了从不一样的栈弹出。至于为什么不能 * 放里面。还是个疑问。懂了,画个图就知道,如果弹到u,有可能 * 别的块也被弹出来了,结果错,必须弹到v为止,才是最干净的。 */
View Code
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 const int MAXN = 10015; 6 vector<int> vec[MAXN]; 7 int myS[MAXN], top; 8 int dfn[MAXN], low[MAXN], step; 9 int block[MAXN]; 10 11 //deal_cricle 12 int vst[MAXN], inBlock[MAXN]; 13 int sol1, sol2; 14 15 void addEdge(int u, int v) 16 { 17 vec[u].push_back(v); 18 vec[v].push_back(u); 19 } 20 21 void init() 22 { 23 sol1 = sol2 = 0; 24 step = top = 0; 25 for(int i = 0; i < MAXN; i++) 26 { 27 myS[i] = 0; 28 vec[i].clear(); 29 dfn[i] = low[i] = -1; 30 } 31 } 32 33 void deal_circle() 34 { 35 int edgeNum = 0; 36 memset(vst, 0, sizeof(vst)); 37 memset(inBlock, 0, sizeof(inBlock)); 38 39 for(int i = 1; i <= block[0]; i++) 40 { 41 inBlock[block[i]] = 1; 42 } 43 44 for(int i = 1; i <= block[0]; i++) 45 { 46 int u = block[i]; 47 for(unsigned j = 0; j < vec[u].size(); j++) 48 { 49 int v = vec[u][j]; 50 if(inBlock[v] == 1) 51 edgeNum++; 52 } 53 } 54 edgeNum /= 2; 55 if(edgeNum > block[0]) 56 sol2 += edgeNum; 57 if(edgeNum < block[0]) 58 sol1 += edgeNum; 59 } 60 61 void tarjan_block(int n) 62 { 63 dfn[n] = low[n] = ++step; 64 myS[top++] = n; 65 for(unsigned i = 0; i < vec[n].size(); i++) 66 { 67 int son = vec[n][i]; 68 if(dfn[son] == -1) 69 { 70 tarjan_block(son); 71 low[n] = min(low[n], low[son]); 72 if(low[son] >= dfn[n]) 73 { 74 block[0] = 0; 75 76 while(1) 77 { 78 block[++block[0]] = myS[top - 1]; 79 if(myS[--top] == son) 80 break; 81 } 82 block[++block[0]] = n; 83 deal_circle(); 84 } 85 } 86 else 87 low[n] = min(low[n], dfn[son]); 88 } 89 } 90 91 int main(void) 92 { 93 94 #ifndef ONLINE_JUDGE 95 freopen("in.txt", "r", stdin); 96 #endif 97 98 int n, m; 99 while(scanf("%d %d", &n, &m) != EOF) 100 { 101 if(n == 0 && m == 0) 102 break; 103 104 init(); 105 int u, v; 106 for(int i = 0; i < m; i++) 107 { 108 scanf("%d %d", &u, &v); 109 addEdge(u, v); 110 } 111 112 for(int i = 0; i < n; i++) 113 { 114 if(dfn[i] == -1) 115 tarjan_block(i); 116 } 117 118 printf("%d %d\n", sol1, sol2); 119 } 120 return 0; 121 }