HDU 3849 By Recognizing These Guys, We Find Social Networks Useful 边双连通

题意:有n个人,它们之间有m个关系,关系是相互的,也就是边是无向边,现在问这个无向图有多少个桥,然后把这个桥的两个端点输出出来。


想法:tarjan边双连通,col为总的桥数因为col=0也是一个块,输出桥的端点名字即可。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<map>
using namespace std;
const int N=10000+50;
const int M=200000+50;
int n,m;
struct node
{
	int v,next;
}e[M];
struct nodee
{
	int u,v;
	char name1[20],name2[20];
}rsp[M/2];
map<string,int>mp;
int head[N],cnt;
int low[N],dfn[N],col,index;
stack<int>s;
void Init()
{
	while(!s.empty()) s.pop();
	memset(head,-1,sizeof(head));
	cnt=col=index=0;
	memset(low,0,sizeof(low));
	memset(dfn,0,sizeof(dfn));
}
void add(int a,int b)
{
	e[cnt].v=b;
	e[cnt].next=head[a];
	head[a]=cnt++;
}
int Min(int a,int b)
{
	if(a<b) return a;
	return b;
}
void tarjan(int u,int f)
{
	low[u]=dfn[u]=++index;
	s.push(u);
	for(int i=head[u];i+1;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfn[v]) 
		{
			tarjan(v,u);
			low[u]=Min(low[u],low[v]);
			if(low[v]>dfn[u]) ++col;
		}
		else if(v!=f)
		{
			low[u]=Min(low[u],dfn[v]);
		}
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int num=0;
		mp.clear();
		Init();
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			scanf("%s%s",rsp[i].name1,rsp[i].name2);
			if(!mp[rsp[i].name1]) mp[rsp[i].name1]=++num;
			if(!mp[rsp[i].name2]) mp[rsp[i].name2]=++num;
			int a=mp[rsp[i].name1],b=mp[rsp[i].name2];
			add(a,b);
			add(b,a);
			rsp[i].u=a;
			rsp[i].v=b;
		}
		tarjan(1,-1);
		int mark=1;
		for(int i=1;i<=n;i++)
		{
			if(!dfn[i])
			{
				mark=0;
				break;
			}
		}
		if(!mark)
		{
			printf("0\n");
			continue;
		}
		printf("%d\n",col);
		for(int i=1;i<=m;i++)
		{
			int u=rsp[i].u;
			int v=rsp[i].v;
			if(low[v]>dfn[u]||low[u]>dfn[v]) 
			{
				printf("%s %s\n",rsp[i].name1,rsp[i].name2);
			}
		}
	}
	return 0;
} 


你可能感兴趣的:(HDU 3849 By Recognizing These Guys, We Find Social Networks Useful 边双连通)