【一只蒟蒻的刷题历程】--- 【洛谷】P3388 【模板】割点(割顶)

割点 割边代码相似,稍作修改即可

区别(个人理解):
割点:需要单独判断根是否为割点,有至少2个child即为割点

     判断:low[v]>=dfn[u]  (u为父,v为子)

割边:

     判断:low[v]>dfn[u];(不用考虑根节点)

割边模板题链接

题目描述

给出一个 nnn 个点,mmm 条边的无向图,求图的割点。

输入格式

第一行输入两个正整数 n,mn,mn,m。

下面 mmm 行每行输入两个正整数 x,yx,yx,y 表示 xxx 到 yyy 有一条边。

输出格式

第一行输出割点个数。

第二行按照节点编号从小到大输出节点,用空格隔开。

#include 
#include  
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;  
const int maxn=20050;
int n,m,a,b,low[maxn],dfn[maxn],cnt=0,ans=0;  
vector<int> g[maxn];   
bool vis[maxn]={false};  // true代表为割点 
 
void cut(int u,int father)
{
       low[u]=dfn[u]=++cnt; 
       int child=0;            //记录根的孩子个数 
       for(int i=0;i<g[u].size();i++)
       {
       	   int v=g[u][i];
       	   if(dfn[v])      // v已访问(可能为u的祖先)更新u的low 
       	        low[u]=min(low[u],dfn[v]);
       	    if(!dfn[v])  // v没访问,dfs 
       	    {
       	    	cut(v,u);
       	    	low[u]=min(low[u],low[v]);  //回溯更新u的low(v可以到达过u的祖先并且更新low,而u连接v,u的low值更新(个人理解)) 
       	    	if(dfn[u] <= low[v] && u!=father) //根是否为割点要由child个数判断 
       	    	   vis[u]=1;                      /* v的最小时间戳如果比u大,就代表v不能 
       	    	                                  绕过u到达u的祖先  即为割点 */ 
				   if(u==father)                      
				    child++;          //u为父亲,孩子增加1 
			}
	   }
	   if(child>1 && u==father)  //如果是根,并且有至少2个孩子,就是割点
	     vis[u]=1;
}

int main()
{
   cin>>n>>m;
   while(m--)
   {
   	  cin>>a>>b;
   	  g[a].push_back(b);   //存图 
   	  g[b].push_back(a);
   }
   for(int i=1;i<=n;i++)          //图可能不是连通图,所以一次循环遍历
       if(!dfn[i]) cut(i,i);       
      
   for(int i=1;i<=n;i++)
      if(vis[i]) ans++;       //计数 
    
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)
      if(vis[i]) cout<<i<<" ";  //输出答案 
	return 0;       //愉快的水完一题 
}

你可能感兴趣的:(#,搜索)