求割桥模板题;
割桥定义:一个强连通分量去掉这条边变成多个强连通分量
判断:桥无向边(u,v),当且仅当(u,v)为树枝边,且满足dfn[u]<low[v];
这道题注意是让按升序输出,并且要按照格式输入输出
#include<cstring>
#include<string>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define inf 0x3f3f3f3f
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int N=1e5+5;//数据开的尽量大
const int M=1e6+5;
struct NOde
{
int v,ne;
}edge[M];//存边
int head[N];
int low[N],dfn[N],vis[N];
int e,cut,top,n;
struct Brige
{
int u,v;
}bri[M];//存割桥
bool cmp(Brige a,Brige b)//题目说按升序输出
{
if(a.u==b.u)
return a.v<b.v;
return a.u<b.u;
}
void add(int a,int b)
{
edge[e].v=b;
edge[e].ne=head[a];
head[a]=e++;
}
void init()
{
memset(head,-1,sizeof(head));
e=0;cut=0;
}
void tarjan(int now,int pre)
{
low[now]=dfn[now]=++top;
for(int i=head[now];i!=-1;i=edge[i].ne)
{
int v=edge[i].v;
if(dfn[v]==0)
{
tarjan(v,now);
low[now]=min(low[now],low[v]);
if(dfn[now]<low[v])//判断是否为割桥
{
bri[cut].u=min(now,v);//这里注意!!!!要让小的试起点
bri[cut++].v=max(v,now);
}
}
else if(dfn[v]<dfn[now]&&v!=pre)//如果v已被访问,说明(u,v)室反向边,用反向边更新low
low[now]=min(low[now],dfn[v]);
}
}
void solve()
{
top=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
for(int i=1;i<=n;i++)//图可能不是强连通,要遍历每个点
{
if(dfn[i]==0)
tarjan(i,-1);
}
}
int main()
{
while(~scanf("%d",&n))
{
int a,sum,b;
init();
for(int i=0;i<n;i++)
{
scanf("%d (%d)",&a,&sum);
a++;
for(int j=0;j<sum;j++)
{
scanf("%d",&b);
b++;
add(a,b);
}
}
solve();
printf("%d critical links\n",cut);
sort(bri,bri+cut,cmp);
for(int i=0;i<cut;i++)
printf("%d - %d\n",bri[i].u-1,bri[i].v-1);
printf("\n");
}
return 0;
}