这两道是板子题,我主要看的kuangbin的模板,因为割点与桥是连在一起求的,比较方便。网上也有很多其他的,但是没有找到合适的统一求割点与桥的模板。
附上大佬的博客Orz:
UVA-315:https://www.cnblogs.com/kuangbin/p/3184060.html
UVA-796:http://www.cnblogs.com/kuangbin/archive/2013/07/11/3184068.html
这个模板很全面了,但加边有讲究:正向边与反向边要同时加(相邻),可能因为有异或的操作。
附上一个混合了两道题的AC代码2333:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef pair<int,int> pp;
const int MAXN = 10010;
const int MAXM = 100010;
struct Edge
{
int to,next;
bool iscut;//是否为桥
}edge[MAXM];
int head[MAXN],tot;
int low[MAXN],dfn[MAXN],st[MAXN];
int inde,top;
bool inst[MAXN];
bool iscut[MAXN];
int add_block[MAXN];//删除一个点后增加的连通块
int bridge;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[tot].to=v;edge[tot].next=head[u];edge[tot].iscut=false;
head[u]=tot++;
}
void Tarjan(int u,int pre)
{
int v;
low[u]=dfn[u]=++inde;
st[top++]=u;
inst[u]=true;
int son=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(v==pre)//注意!!
continue;
if(!dfn[v])
{
son++;
Tarjan(v,u);
if(low[u]>low[v])
low[u]=low[v];
//桥
if(low[v]>dfn[u])
{
bridge++;
edge[i].iscut=true;
edge[i^1].iscut=true;
}
//割点
if(u!=pre&&low[v]>=dfn[u])//不是树根
{
iscut[u]=true;
add_block[u]++;
}
}
else if(low[u]>dfn[v])
low[u]=dfn[v];
}
if(u==pre&&son>1)//树根,分支数大于1
iscut[u]=true;
if(u==pre)
add_block[u]=son-1;
inst[u]=false;
top--;
}
void solve(int n)
{
memset(dfn,0,sizeof(dfn));
memset(inst,false,sizeof(inst));
memset(add_block,0,sizeof(add_block));
memset(iscut,false,sizeof(iscut));
inde=top=0;
bridge=0;
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(i,i);
int cut=0;//割点
for(int i=1;i<=n;i++)
if(iscut[i])
{
//printf("%d\n",i);
cut++;
}
printf("%d\n",cut);
printf("%d critical links\n",bridge);//桥
vector<pp>ans;
for(int u=1;u<=n;u++)
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].iscut&&v>u)
ans.push_back(make_pair(u,v));
}
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
printf("%d - %d\n",ans[i].first-1,ans[i].second-1);
printf("\n");
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
init();
//要保证正边和反边是相邻的,建无向图
//UVA315
int g[105][105];
memset(g,0,sizeof(g));
int u,v;
scanf("%d",&u);
while(u!=0)
{
while(getchar()!='\n')
{
scanf("%d",&v);
addedge(u,v);
addedge(v,u);//无向图
}
scanf("%d",&u);
}
//UVA796
int u,v,k;
for(int i=1;i<=n;i++)
{
scanf("%d (%d)",&u,&k);
u++;
while(k--)
{
scanf("%d",&v);
v++;
if(v<=u)//判重
continue;
addedge(u,v);
addedge(v,u);
}
}
solve(n);
}
return 0;
}