HDU3394 Railway 求块 判断环

对于我来说真是一道好题,一开始纠结为缩点跟求块,最后还是一个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 }
原文地址:https://www.cnblogs.com/cchun/p/2641076.html