poj 3177 割边(双连通分量)

题意:求最少添加多少条边可变无桥的连通图。

思路:求出所有的双连通分量(块),然后进行缩点。所求为缩点后的图的叶子数量加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;
}



你可能感兴趣的:(poj 3177 割边(双连通分量))