题意:给定一个连通图,求至少加几条边使得整个图成为边双联通图。
思路:先求出桥,对图中边双连通分量缩点,得到一棵树,求得树的叶子数为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 ",(ans + 1) / 2); return 0; }