UVA 315 Tarjan求割点

题意:

一个无向连通图,若去掉某个点后这个图变成了非连通图,这个点成为关键点,求关键点的数目。

题解:

1.关键点就是割点,套用Tarjan模板:https://www.cnblogs.com/collectionne/p/6847240.html

#include <bits/stdc++.h>
#define N 105
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
int n ;
bool vis[N] ;
int low[N] ;
int dfn[N] ;
int parent[N] ;
bool cut_point[N] ;
vector <int> edge[N] ;
void Tarjin(int u , int m)
{
    int i , j ;
    int v ;
    int children = 0 ;
    vis[u] = 1 ;
    dfn[u] = m ;
    low[u] = m ;
    for(i = 0 ; i < edge[u].size() ; i ++)
    {
        v = edge[u][i] ;
        if(!vis[v])
        {
          children ++ ;
          parent[v] = u ;
          Tarjin(v , m + 1) ;
          low[u] = min(low[u] , low[v]) ;
          if(parent[u] == -1 && children >= 2) //u是根节点且子树数目大于等于2
             cut_point[u] = 1 ;
          if(parent[u] != -1 && low[v] >= dfn[u]) //u不是根节点且子节点的low不小于自己的dfn
             cut_point[u] = 1 ;
        }
        else if(parent[u] != v)
           low[u] = min(low[u] , dfn[v]) ;
    }
}
int main()
{
    int i , j ;
    int u , v ;
    int ans = 0 ;
    char c ;
    while(scanf("%d" , &n) && n != 0)
    {
        for(i = 1 ; i <= n ; i ++)
            edge[i].clear() ;
        while(scanf("%d" , &u) && u != 0)
        {
            while(1)
            {
                scanf("%d%c" , &v , &c) ;
                edge[u].push_back(v) ;
                edge[v].push_back(u) ;
                if(c == '\n')
                   break ;
            }
        }
        memset(low , inf , sizeof(low)) ;
        memset(dfn , inf , sizeof(dfn)) ;
        memset(parent , -1 , sizeof(parent)) ;
        memset(vis , 0 , sizeof(vis)) ;
        memset(cut_point , 0 , sizeof(cut_point)) ;
        Tarjin(1 , 1) ;
        ans = 0 ;
        for(i = 1 ; i <= n ; i ++)
            if(cut_point[i])
              ans ++ ;
        printf("%d\n" , ans) ;
    }
}

 

Tarjan算法是一种用于解决最近公共祖先(LCA)问题的离线算法。离线算法指的是在读取所有查询之后一次性计算所有查询的答案,而不是每读取一个查询就计算一次。\[1\] 在Tarjan算法中,需要使用并查集来实现。并查集是一种数据结构,用于维护元素之间的集合关系。下面是一个并查集的模板代码: ```cpp int fa\[100000\]; void reset(){ for (int i=1;i<=100000;i++){ fa\[i\]=i; } } int getfa(int x){ return fa\[x\]==x?x:getfa(fa\[x\]); } void merge(int x,int y){ fa\[getfa(y)\]=getfa(x); } ``` 在Tarjan算法的伪代码中,首先标记当前节点为已访问状态。然后遍历当前节点的子节点,递归调用Tarjan函数并合并子节点。接下来,遍历与当前节点有查询关系的节点,如果该节点已经访问过,则输出当前节点和该节点的LCA(通过并查集的查找函数getfa获取)。\[3\] 以上是关于Tarjan算法解LCA的相关内容。 #### 引用[.reference_title] - *1* [Tarjan 算法解决 LCA 问题](https://blog.csdn.net/chengqiuming/article/details/126878817)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [详解使用 Tarjan LCA 问题(解)](https://blog.csdn.net/weixin_34315485/article/details/93801193)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值