现在的位置: 首页 > 综合 > 正文

POJ 2117 Electricity (tarjan)删割点后求块数

2014年01月22日 ⁄ 综合 ⁄ 共 1496字 ⁄ 字号 评论关闭
/**
*      tarjan: 求一个图中删除一个割点后所得到的最大块数。
*   在用tarjan去遍历每个结点的时候,判断割点是如何判断的?
*   low[v] >= dfn[u] (这里注意不要和求割边混淆)
*   求割边的时候,是以low[v] > dfn[u]. 这个其实可以画下图就很好理解了。
*      割点的定义是,删除该结点以及和该结点相关联的边。
*   所以用low[v] >= dfn[u] 需要等号。 因为,即使u的子结点能够通过一个环而返回到u结点。
*   也是可以的,因为在连回u的时候,仍然是u的关联边。所以在判断u是否为割点的时候,是同结点u一同删除的。
*      然而割边的定义是,删除该边使图不连通。所以不能使u的子结点连回u的祖先和u本身!
*   所以是low[v] > dfn[u]。
*      现在的问题是如何计算删除该割点后的块的数量。
*   实际上只要在遍历当前结点u的时候。 计数出通过该结点引出的边的数量,使得low[v] >= dfn[u]
*   (当low[v] = dfn[u]的时候,其实是有两条或者两条以上的边属于当前节点u的关联边,但实际上也只算了一次。)
*      还有就是考虑到给的图不是连通图。这个好解决,因为在tarjan遍历的时候,必然是遍历每个连通分量的。
*   扫一遍所有节点,计数就行了。
*   不明白的画图理解即可。 其他具体实现看代码。
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x1fffffff
#define MAXS 10005

typedef long long LL;
using namespace std;

int dfn[MAXS], low[MAXS];
int n, m, ans;
vector<int> ver[MAXS];
int DFN;
void tarjan(int u, int fa)
{
    int cnt = 0, son = 0;
    dfn[u] = low[u] = ++ DFN;
    for(int i = 0; i != ver[u].size(); i ++)
    {
        int v = ver[u][i];
        if(!dfn[v])
        {
            son ++;
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u])
            {
                cnt ++;
            }
        }
        else if(v != fa && dfn[v] < low[u])
            low[u] = min(low[u], dfn[v]);
    }
    if(fa != -1)
        cnt ++;
    if(fa == -1 && son <= 1)
        cnt = 0;
    ans = max(cnt, ans);
}

void init()
{
    DFN = 0;
    for(int i = 0; i <= n; i ++)
    {
        ver[i].clear();
        dfn[i] = low[i] = 0;
    }
}

int main()
{
    //freopen("e.in", "r", stdin);
    while(cin >> n >> m, n + m)
    {
        init();
        for(int i = 1; i <= m; i ++)
        {
            int v, u;
            cin >> v >> u;
            ver[v].push_back(u);
            ver[u].push_back(v);
        }
        int cnt = 0;
        ans = 0;
        if(m == 0) {
            printf("%d\n", n - 1);
            continue;
        }
        for(int i = 0; i < n; i ++) {
            if(!dfn[i]) {
                tarjan(i, -1);
                cnt ++;
            }
        }

        if(ans) cnt --;
        cout << ans + cnt << endl;
    }
    return 0;
}

抱歉!评论已关闭.