码迷,mamicode.com
首页 > 其他好文 > 详细

边双连通分量模板题

时间:2020-04-11 20:10:18      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:个数   head   highlight   next   const   cstring   add   ring   ==   

1:POJ3353 Road Construction

此题没有重边

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010
#define M 2020
using namespace std;
struct KSD
{
	int v,next;
}e[M];
int head[N],cnt;
inline void add(int u,int v)
{
	e[++cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int dfn[N],low[N],n,m;
int id[N],group,d[N];
int ans,edges; // 边-双个数、 桥个数
int stk[N],top;

void tarjan(int x,int p) 
// 边双连通分量,即无桥。
{
	int i,v,temp;
	dfn[x]=low[x]=++cnt;
	stk[++top]=x;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		if(v==p)continue;
		if(!dfn[v])
		{
			tarjan(v,x);
			low[x]=min(low[x],low[v]);
		}
		else low[x]=min(low[x],dfn[v]);
//		if(dfn[x]<low[v])edges++; // 桥的数目
	}
	if(dfn[x]==low[x])
	{
		group++;
		do{
			temp=stk[top--];
			id[temp]=group;
			//第temp个点属于第group个连通块 
		}while(temp!=x);
	}
	return ;
}

int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(head,0,sizeof(head));
		memset(dfn,0,sizeof(dfn));
		memset(d,0,sizeof(d));
		cnt=group=ans=0;

		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&a,&b);
			add(a,b),add(b,a);
		}
		cnt=0;
		for(i=1;i<=n;i++)
		     if(!dfn[i])
			     tarjan(i,0);
		for(j=1;j<=n;j++)
			for(i=head[j];i;i=e[i].next)
				if(id[j]!=id[e[i].v])
				//有一条边从J-->e[i].v
				//e[i].v的入度加1 
				   d[id[e[i].v]]++;
		for(i=1;i<=n;i++)
		   if(d[i]==1)
		      ans++;

		printf("%d\n",(ans+1)>>1);
	}

	return 0;
}

  

边双连通分量模板题

标签:个数   head   highlight   next   const   cstring   add   ring   ==   

原文地址:https://www.cnblogs.com/cutemush/p/12681872.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!