题意:
无向图求割边~(桥)
输入是图中所有边(按顺序)的顶点编号,对每个案例,输出桥的个数,及边的编号。
分析:
本题由于有重边,故不能用邻接矩阵存储图,必须用邻接表!
处理重边很简单:只要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;
}