加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 1144 割点个数

(2010-10-02 10:30:47)
标签:

poj

pku

1144

割点个数

it

分类: 图论

题目描述:求个点个数。

解题报告:

结合tarjan算法的定义:

low[i]<dfn[m]表示i结点能够到达的最低深度可以比m小,也就是说i结点可以通过某条路径(这个应该是后向边)到达深度比m小的结点,

也就是说如果m点去掉,i结点还是可以通过其他的路径与m结点的上方的结点相连,并没有因为m的除掉而成为孤立的一部分脱离整个图形。

low[i]== dfn [m]表示i结点能够到达的最低深度就是m,在这棵树上没有能够到达m上方的结点的后向边,如果m除掉后,那么很显然i结点

(以及他的下部分)会脱离整个原来的图

如果low[i]> dfn [m]这个就更显然了,他没有可以到达比m结点还要低深度的结点的路径,那么m去掉后只能孤立与原图。

根节点比较特殊,因为跟结点与他的儿子都满足low[i]>= dfn [m],所以根节点要做特殊的处理

求割点的时候由于不知道最开始选的树根是不是只有一个儿子,这样在DFS过来中不会满足low[u]>=dfn[v]而判为割点,但有两个或两个以上儿子的根肯定也是一个割点,所以要特判!

代码如下:

#include<iostream>
using namespace std;
struct edge{int to, next;}e[200000];
int n, v[110], cnt, index, ans, root, dfn[110], low[110];
bool vst[110];
void insert(int from, int to)
{
    e[cnt].to = to, e[cnt].next = v[from]; v[from] = cnt++;
}
void jeo(int id)
{
    dfn[id] = low[id] = ++index;
    for(int i = v[id]; i != -1; i = e[i].next)
        if (!dfn[e[i].to])
        {
            jeo(e[i].to);
            low[id] = min(low[id], low[e[i].to]);
            if (low[e[i].to] >= dfn[id] && id != 1)
                vst[id] = 1;
            else if (id == 1) root++;
        }
        else low[id] = min(low[id], dfn[e[i].to]);
}
int main()
{
    while(scanf("%d", &n) && n)
    {
        int id;
        memset(v, -1, sizeof(int) * (n + 1)); cnt = 0;
        while(scanf("%d", &id) && id)
            while(getchar() != '\n')
            {
                int tmp; scanf("%d", &tmp);
                insert(id, tmp), insert(tmp, id);
            }
        memset(dfn, 0, sizeof(int) * (n + 1));
        root = ans = index = 0;
        memset(vst, 0, sizeof(bool) * (n + 1));
        jeo(1);
        for(int i = 2; i <= n; i++) ans += vst[i];
        ans += (root > 1);
        printf("%d\n", ans);
    }
    return 0;
}

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有