给出一个n个点,m条边的无向图,求图的割点。
第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
1
5
n,m均为100000
tarjan 图不一定联通!!!
求割点的模板题,说明几个要注意的地方:
对于根节点,判断是不是割点很简单——计算其子树数量,如果有2棵即以上的子树,就是割点。因为如果去掉这个点,这两棵子树就不能互相到达。
low[v]>=dfn[u]
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=100010*2;
int low[N],dfn[N],dfs_num;
int tot,son;
int subnets[N],vis[N],root,first[N];
struct edge
{
int v,next;
} e[N*10];
void init()
{
mem(first,-1);
tot=0;
}
void add(int u,int v)
{
e[tot].v=v;
e[tot].next=first[u];
first[u]=tot++;
}
void get_cut_point(int u)//求割点
{
if(u!=root)
subnets[u]++;
else son++;
}
void dfs(int u)
{
low[u]=dfn[u]=++dfs_num;
vis[u]=1;
for(int i=first[u]; ~i; i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
//求割点
if(low[v]>=dfn[u])
get_cut_point(u);//割点
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
}
int main()
{
int n,m,u,v;
scanf("%d%d",&n,&m);
init();
for(int i=1; i<=m; i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
{
root=i;
son=0;
dfs(i);
if(son>1)
subnets[i]=1;
}
int cnt=0;
for(int i=1; i<=n; i++)
if(subnets[i])
cnt++;
printf("%d\n",cnt);
for(int i=1; i<=n; i++)
if(subnets[i])
printf("%d ",i);
return 0;
}
2018年01月22日重构代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define inf 1000000
#define mem(a,b) memset(a,b,sizeof(a))
const int N=100000+7;
const int M=2*100000+20;
int dfn[N],low[N],times;
int root,son;
int n,m;
int first[N],tot,subnets[N];
struct edge
{
int v;
int next;
} e[M];
void add_edge(int u,int v)
{
e[tot].v=v;
e[tot].next=first[u];
first[u]=tot++;
}
void init()
{
mem(dfn,0);
mem(low,0);
mem(first,-1);
mem(subnets,0);
tot=0;
times=0;
}
void tarjan(int u)
{
low[u]=dfn[u]=++times;
for(int i=first[u]; ~i; i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
if(u==root)
son++;
else
subnets[u]++;
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
int main()
{
int u,v;
init();
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
{
root=i;
son=0;
tarjan(i);
if(son>1)
subnets[i]=1;
}
int sum=0;
for(int i=1; i<=n; i++)
if(subnets[i])
sum++;
printf("%d\n",sum);
for(int i=1; i<=n; i++)
if(subnets[i])
printf("%d ",i);
return 0;
}