题意:求最少添加多少条边可变无桥的连通图。
思路:求出所有的双连通分量(块),然后进行缩点。所求为缩点后的图的叶子数量加1,再除以2。要点:属于同一双连通分支的点的low值必相同。求双连通分量时可以不用dfn数组。
注意:题目中有重边,可以用邻接矩阵判断一下重;存在临界表时判断一下也不会超时。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 5005
#define M 10005
int n,m,top;
bool flag[N][N];
int low[N],first[N];
int id,d[N];
struct edge{
int y,next;
}e[M<<1];
void add(int x,int y){
e[top].y = y;
e[top].next = first[x];
first[x] = top++;
}
void tarjan(int x,int fa){
int i;
low[x] = ++id;
for(i = first[x];i!=-1;i=e[i].next){
if(e[i].y == fa)
continue;
if(low[e[i].y] == -1)
tarjan(e[i].y,x);
low[x] = min(low[x] , low[e[i].y]);
}
}
int main(){
int i,j,a,b,res=0;
top = id = 0;
memset(first, -1, sizeof(first));
memset(d, 0, sizeof(d));
memset(low, -1, sizeof(low));
scanf("%d %d",&n,&m);
for(i = 1;i<=m;i++){
scanf("%d %d",&a,&b);
if(!flag[a][b]){
add(a,b);
add(b,a);
flag[a][b] = flag[b][a] = true;
}
}
tarjan(1,-1);
for(a = 1;a<=n;a++)
for(j = first[a];j!=-1;j=e[j].next){
b = e[j].y;
if(low[a] != low[b])
d[low[a]]++;
}
for(i = 1;i<=n;i++)
if(d[i] == 1)
res++;
printf("%d\n",(res+1)/2);
return 0;
}
int test(int x,int y){
int i;
for(i = first[x];i!=-1;i=e[i].next)
if(e[i].y == y)
return 1;
return 0;
}