ZOJ 2588 : Burning Bridges - 无向图求割边(裸)

题意:
无向图求割边~(桥)
输入是图中所有边(按顺序)的顶点编号,对每个案例,输出桥的个数,及边的编号。
分析:
本题由于有重边,故不能用邻接矩阵存储图,必须用邻接表!
处理重边很简单:只要u,v间有重边,那么这些重边任何一条都不可能是桥。

下面代码,从顶点0出发进行一次dfs,并求出每个顶点dfn[u]和low[u]。
对除重边外的每条生成树中的边(u,v),若满足dfn[u]<low[v],则边(u,v)是桥。

#include <iostream>
#include <stdio.h>
#include <string.h>
#define clr(a) memset(a,0,sizeof(a))
#define Min(a,b) ((a)>(b)?(b):(a))
#define maxn 10005
#define maxm 100005
using namespace std;
int bridge[maxm];
struct node
{
	int j,id,tag;
	node* next;
};
node* e[maxn];int n,m,nid,nbridge;node mem[maxm*2];int memp;
int low[maxn];int dfn[maxn];int vis[maxn];
int addedge(node* e[],int i,int j)
{
	node* p;
	for(p=e[i];p!=NULL;p=p->next)
	{
		if(p->j==j) break;
	}
	if(p!=NULL) {p->tag++;return 0;}
	else{	p=&mem[memp++];
	p->j=j;p->next=e[i];e[i]=p;p->id=nid;p->tag=0;
	return 1;}
}
void dfs(int i,int fa,int dth)
{
	vis[i]=1;dfn[i]=low[i]=dth;
	node* p;
	for(p=e[i];p!=NULL;p=p->next)
	{
		int j=p->j;
		if(j!=fa&&vis[j]==1)
		{
			low[i]=min(low[i],dfn[j]);
		}
		if(!vis[j])
		{
			dfs(j,i,dth+1);
			low[i]=min(low[i],low[j]);
			if(low[j]>dfn[i]&&!p->tag)
			{
				bridge[p->id]=++nbridge;
			}
		}
	}
	//vis[i]=2;
}
int main()
{
	int t,k,i,j;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		clr(e);
		memp=0;nid=0;
		for(k=0;k<m;k++,nid++)
		{
			scanf("%d%d",&i,&j);
			addedge(e,i-1,j-1);addedge(e,j-1,i-1);
			bridge[nid]=0;
		}
		nbridge=0;clr(vis);
		dfs(0,-1,1);
		printf("%d\n",nbridge);
		for(k=0,i=nbridge;k<m;k++)
		{
			if(bridge[k]) {
				printf("%d",k+1);
				if(--i) printf(" ");
			}
		}
		if(nbridge) printf("\n");
		if(t) printf("\n");
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值