现在的位置: 首页 > 综合 > 正文

poj 3177 (双联通)

2018年03月18日 ⁄ 综合 ⁄ 共 1218字 ⁄ 字号 评论关闭

第一道双联通的题目,求加几条边让原图成一个双联通图,求出度数为1的双联通分量的个数+1/2、

Low[u]为u或u的子树中能通过非父子边追溯到的最早的节点,即DFS序号最小的节点的序号







#include<stdio.h>
#include<stack>
#include<string.h>
#define N 5010
using namespace std;
int n,m,first[N],num,low[N],dfs[N],idx,ans,vis[N],degree[N],belong[N];
struct edge
{
	int ed,next;
}E[10010];
void addedge(int x,int y)
{
	E[num].ed=y;
	E[num].next=first[x];
	first[x]=num++;
}
stack<int>Q;
void Tarjan(int u,int father)
{
	
	low[u]=dfs[u]=idx++;
	vis[u]=1;
	Q.push(u);
	for(int p=first[u];p!=-1;p=E[p].next)
	{
		int v=E[p].ed;
		if(v==father){continue;}
		if(!vis[v])Tarjan(v,u);
		low[u]=low[u]>low[v]?low[v]:low[u];
	}
	int x;
	if(low[u]==dfs[u])
	{
		do
		{
			x=Q.top();
			Q.pop();
			vis[x]=0;
			belong[x]=ans;//缩点
		}while(x!=u);
		ans++;
	}
}
int judge(int x,int y)
{
	for(int p=first[x];p!=-1;p=E[p].next)
		if(E[p].ed==y)
			return 0;
		return 1;
}
int main()
{
	int i,x,y,sum;
	while(scanf("%d%d",&n,&m)!=-1)
	{
		memset(first,-1,sizeof(first));
		num=0;
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&x,&y);
			if(judge(x,y)==1)//去掉重边
			{
				addedge(x,y);
				addedge(y,x);
			}
		}
		memset(vis,0,sizeof(vis));
		idx=ans=0;
		Tarjan(1,0);
		memset(degree,0,sizeof(degree));
		for(i=1;i<=n;i++)
		{
			for(int p=first[i];p!=-1;p=E[p].next)
			{
				int v=E[p].ed;
				if(belong[i]!=belong[v])
					degree[belong[v]]++;
			}
		}
		sum=0;
		for(i=0;i<ans;i++)
			if(degree[i]==1)//度为1的点
				sum++;
			//printf("%d\n",sum);
			printf("%d\n",(sum+1)/2);
	}
	return 0;
}

抱歉!评论已关闭.