BZOJ1718 POJ 3177

题意:给定一个连通图,求至少加几条边使得整个图成为边双联通图。

思路:先求出桥,对图中边双连通分量缩点,得到一棵树,求得树的叶子数为leaf,答案即为(leaf + 1) / 2

代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define N (10010)
#define maxn (N + 5)
#define pii pair<int,int> 
#define mp make_pair
const ll mod = 1000000007;
const ll INF = (1e9);
struct edge{
    int v,nxt;
}e[maxn * 2];
int head[maxn],en;
int sta[maxn],top;
int pre[maxn],low[maxn],clk;
int bel[maxn],bn;
bool vis[maxn];
int du[maxn];
void tarjan(int x,int fa){
    pre[x] = low[x] = ++clk;sta[++top] = x;
    for(int i = head[x];i != -1;i = e[i].nxt){
        int v = e[i].v;
        if(v == fa)continue;
        if(!pre[v]){
            tarjan(v,x);
            low[x] = min(low[x],low[v]);
            if(low[v] > pre[x]){
                vis[i] = true;vis[i ^ 1] = true;
            }
        }
        else{
            low[x] = min(low[x],pre[v]);
        }
    }
    if(pre[x] == low[x]){
        bn++;int v;
        do{
            v = sta[top--];
            bel[v] = bn;
        }
        while(top && x != v);
    }
}
void adde(int u,int v){
    e[en].v = v;e[en].nxt = head[u];head[u] = en++;
}
int main(){
    memset(head,-1,sizeof(head));en = 0;
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i++){
        int u,v;scanf("%d%d",&u,&v);adde(u,v);adde(v,u);
    }
    clk = 0;top = 0;bn = 0;
    tarjan(1,-1);
    for(int i = 1;i <= n;i++){
        for(int j = head[i];j != -1;j = e[j].nxt){
            if(vis[j])du[bel[e[j].v]]++;
        }
    }
    int ans = 0;
    for(int i = 1;i <= bn;i++){
        ans += (du[i] == 1);
    }
    printf("%d\n",(ans + 1) / 2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cleanerhgf/p/12308191.html