【割点 && dfs】UVALive - 7456 Least Crucial Node

Problem Description

给你n,s,m分别代表n个点,s为特殊点,m条边。让你求去掉那个点?使得其他点不能到达s点的点最多。如果存在割点,一样多的。输出编号最小的。

思路:

割点的条件, low[to] >= low[u],u就是割点。所以我们求出割点后,我们可以根据这个条件去dfs,low[to]>=low[u]的to点,这些点都不能到达特殊点。我们记录个数。求出最大个数对应的割点(编号最小)。还有一个割点条件,就是根结点是割点,这个题目如果根结点是割点直接输出1就好了。

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int to, next;
};
node Map[100055];
int head[100055], low[150], dfn[150], flag[150], vis[150];
int inde, s;
void dfs(int u, int father)//求割点,用flag[]标记起来
{
    int child = 0;
    low[u] = dfn[u] = inde++;
    for(int i = head[u]; ~i; i = Map[i].next)
    {
        int to = Map[i].to;
        if(!dfn[to])
        {
            child++;
            dfs(to, u);
            low[u] = min(low[u], low[to]);
            if(u != s && low[to] >= dfn[u])//儿子回不到祖先,代表父亲是割点
            {
                flag[u] = 1;
            }
            if(u == s && child == 2)//根结点,有两个儿子的话,自己就是割点
                flag[u] = 1;
        }
        else if(to != father)//这句话可以不用。
        {
            low[u] = min(low[u], dfn[to]);
        }
    }
    return;
}
int ddf(int u, int ff)//求该割点分离了多少个点,
{
    vis[u] = 1;
    int red = 0;
    for(int i = head[u]; ~i; i = Map[i].next)
    {
        int to = Map[i].to;
        if(low[to] >= dfn[ff] && !vis[to])//满足割点条件继续走
        {
            red = ddf(to, ff) + 1;
        }
    }
    return red;//返回分离了多少个点
}
void add(int u, int v, int &cnt)
{
    Map[cnt].to = v;
    Map[cnt].next = head[u];
    head[u] = cnt++;
}
int main()
{
    int n, m, u, v;
    while(~scanf("%d", &n) && n)
    {
        scanf("%d %d", &s, &m);
        int cnt = 0;
        memset(head, -1, sizeof(head));
        memset(flag, 0, sizeof(flag));
        memset(dfn, 0, sizeof(dfn));
        while(m--)
        {
            scanf("%d %d", &u, &v);
            add(u, v, cnt);
            add(v, u, cnt);
        }
        inde = 1;
        dfs(s, s);
        int Max = 0, sum, ans = 1;
        for(int i = 1; i <= n; i++)//求分离最多点的割点。同样多的话,选择编号最小的。
        {
            if(flag[i] == 1)
            {
                memset(vis, 0, sizeof(vis));
                sum = ddf(i, i);
                if(sum > Max)
                {
                    Max = sum;
                    ans = i;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值