题意:求割点和桥。。就是裸的。。
思路:Tarjan。。。因为是裸的吗,那我就写一下Tarjan如何求割点和桥吧,我们知道Tarjan有两个数组,low和dfn,其中low[u]表示的是u点可以到达的最早访问的点,dfn表示的访问的顺序,那么当low[v] >=dfn[u](u是父亲,v是儿子)那么就表示v点在不通过u点情况下不能到达比u点更早的点,那么就表明u点是一个割点,第二种情况,就是u是根节点,且他有多于两个儿子,那么这个点就是割点,画个树就知道了,跟节点连接了大于两棵的子树删掉根节点的话,就会变成两颗互不相连的树。
(ps:hihocoder 的数据,好严格,,错一点都过不去,虽然是到裸题,,但是自己扣好久,。。。)
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxnV = 20000+10;
const int maxnE = 100000+10;
struct node
{
int to,nex;
}edg[maxnE*3];
struct point
{
int x,y;
}P[maxnV];
int head[maxnV],low[maxnV],dfn[maxnV];
int instack[maxnV],Index,cnt,belong[maxnV],scc,num[maxnV];
int in[maxnV],out[maxnV],cur,Root;
int Flag = 0;
void init()
{
Index = 0;
Root = 1;
cnt = 0;
scc = 0;
cur = 0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
//memset(in,0,sizeof(in));
memset(belong,0,sizeof(belong));
//memset(out,0,sizeof(out));
memset(low,0,sizeof(low));
//memset(instack,0,sizeof(instack));
}
void add(int u,int v)
{
edg[cnt].to = v;
edg[cnt].nex = head[u];
head[u] = cnt++;
}
bool cmp(point a,point b)
{
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
void tarjan(int u,int father)
{
int child = 0;
low[u] = dfn[u] = ++Index;
for(int i = head[u] ; i!=-1 ; i = edg[i].nex)
{
int v = edg[i].to;
if(!dfn[v])
{
child++;
tarjan(v,u);
low[u] = min(low[u],low[v]);
if((u != Root && low[v] >= dfn[u])||(u == Root && child > 1))
{
belong[u] = 1;
}
if(low[v] > dfn[u])
{
P[cur].x = min(u,v);
P[cur].y = max(u,v);
cur++;
}
}
else if(v != father)low[u] = min(low[u],dfn[v]);
}
}
int main()
{
int n,m,a,b;
scanf("%d%d",&n,&m);
Root = 1;
cur = 0;
init();
for(int i = 0 ; i < m;i++)
{
cin>>a>>b;
add(a,b);
add(b,a);
}
for(int i = 1 ; i <= n ;i++)
{
if(!dfn[i])
{
tarjan(i,Root);
}
}
int flag = 0 ;
// if(Flag) puts("Null");
int ff = 0 ;
for(int i = 1 ; i <= n ; i++)
{
if(belong[i])
{
ff = 1;
printf("%d ",i);
}
}
if(!ff) printf("Null\n");
else puts("");
sort(P,P+cur,cmp);
for(int i = 0 ; i < cur ; i++)
{
printf("%d %d\n",P[i].x,P[i].y);
}
}