题目来自洛谷
题目背景
割点
题目描述
给出一个nn个点,mm条边的无向图,求图的割点。
输入输出格式
输入格式:
第一行输入n,mn,m
下面mm行每行输入x,yx,y表示xx到yy有一条边
输出格式:
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入样例#1:
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出样例#1:
1
5
说明
对于全部数据,n \le 20000n≤20000,m \le 100000m≤100000
点的编号均大于00小于等于nn。
tarjan图不一定联通。(特别要注意这里,被坑了~~)
代码改编自啊哈算法
#include<bits/stdc++.h>
using namespace std;
struct node{
int v;//u->v
int naxt;
}a[200005];int head[20005];//数组链表
int c;
void addage(int x,int y)
{
a[++c].v =y;a[c].naxt =head[x];head[x]=c;
a[++c].v =x;a[c].naxt =head[y];head[y]=c;
return;//无向图
}
int n,m,indexx,root,countt;int low[20005],num[20005],flag[20005];
void dfs( int cur, int father )
{
int child=0,j;
indexx++;
num[cur]=indexx;
low[cur]=indexx;
for(j=head[cur];j!=-1;j=a[j].naxt ){
if(num[a[j].v ]==0)
{
child++;
dfs(a[j].v ,cur);
low[cur]=min(low[cur],low[a[j].v ]);
if(cur!=root&&low[a[j].v ]>=num[cur])
{
flag[cur]=1;
}
if(cur==root&&child>=2)//child指的是dfs中生成树中的孩子
{
flag[cur]=1;
}
}
else //if(a[j].v !=father)
low[cur]=min(low[cur],num[a[j].v ]);
}
return;
}
int main(void)
{
int i,x,y;
scanf("%d %d",&n,&m);
c=0;indexx=0;countt=0;
memset(head,-1,sizeof(head));//链表的初始化
memset(flag,0,sizeof(flag));
memset(num,0,sizeof(num));
for(i=1;i<=m;i++){
scanf("%d %d",&x,&y);
addage(x,y);
}
root=1;
for(i=1;i<=n;i++)
if(num[i]==0)
{
root=i;//因为图不连通,那么每次图的根就要跟着变
dfs(i,root);//因为题中说图不一定联通
}//一直A不了就是卡在这里
for(i=1;i<=n;i++)
if(flag[i])
countt++;
printf("%d\n",countt);
for(i=1;i<=n;i++)
if(flag[i])
printf("%d ",i);
//printf("\n");
return 0;
}
上面的是割点的模板,割边是一样的,只需要把low[a[j].v ]>=num[cur]改成low[a[j].v ]>num[cur]即此边为割边