题目链接:http://poj.org/problem?id=3177
题意:至少加多少边才能构成边双连通图。
思路:求边双连通分量,对于每一个边双连通分量都看做一个点,也就是进行缩点,然后就构造出一个树,然后在这个树上加多少个树边,能够变成一个双连通图。 加的数量就是( 这棵树总度数为1的结点数 + 1 )/ 2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int M_node = 5009,M_edge = 20009;
struct edge
{
int to,next;
bool cut;
}edge[M_edge];
stack<int> st;
int head[M_node],tot;
int low[M_node],dfn[M_node],belong[M_node];
int degree[M_node];
int dfs_clock,block,bridge;
bool instack[M_node];
int n,m;
void init()
{
while(!st.empty()) st.pop();
memset(head,-1,sizeof(head));
memset(degree,0,sizeof(degree));
tot = 0;
memset(instack,false,sizeof(instack));
memset(belong,-1,sizeof(belong));
dfs_clock = 0;
block = bridge = 0;
}
void add_edge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].cut = false;
head[u] = tot++;
}
void tarjan(int u,int fa)
{
low[u] = dfn[u] = ++dfs_clock;
st.push(u);
instack[u] = true;
for(int i = head[u]; i != -1 ;i = edge[i].next)
{
int v = edge[i].to;
if(v == fa) continue;
if(!dfn[v])
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u])
{
bridge++;
edge[i].cut = true;
edge[i^1].cut = true;
}
}
else if(instack[u] && low[u] > dfn[v]) low[u] = dfn[v];
}
if(low[u] == dfn[u])
{
block++;
for(;;)
{
int v = st.top();
st.pop();
instack[v] = false;
belong[v] = block;
if(v == u) break;
}
}
}
void solve()
{
int ans = 0;
tarjan(1,-1);
for(int i = 1;i <= n;i++)
{
for(int j = head[i];j != -1;j = edge[j].next)
{
if(edge[j].cut) degree[belong[i]]++;
}
}
for(int i = 1;i <= block;i++)
{
if(degree[i] == 1) ans++;
}
printf("%d\n",(ans+1)/2);
}
int main()
{
while(scanf("%d %d",&n,&m) == 2)
{
init();
for(int i = 0;i < m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
add_edge(a,b);
add_edge(b,a);
}
solve();
}
return 0;
}
时间: 2024-10-13 07:54:48