POJ 3352 Road Construction

来源:互联网 发布:百威进销存软件怎么样 编辑:程序博客网 时间:2024/05/18 14:43

题目来源:http://poj.org/problem?id=3352

题目大意:给定一个无向连通图,问添加几条边可以让其变为边双连通的。

首先应找出所有桥(割边),每个桥连接两个边双连通分量。

将每个双连通分量染色,进行缩点操作。

缩点后,整个图变为了一棵树。题目也就转化为了添加最少的边数使得这棵树为双连通的。

最少增加的边数即为(叶子节点数+1)/2,即图中(度为1的节点个数+1)/2。

代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=1e3+10;int n,m;int cnt=0;struct data{int to,next;}e[maxn*5];int head[maxn];bool cut[maxn][maxn];int dfn[maxn];int low[maxn];int vis[maxn];void cut_bridge(int cur,int fa,int dep){vis[cur]=1;dfn[cur]=low[cur]=dep;for(int i=head[cur];i;i=e[i].next){int x=e[i].to;if(vis[x]==1&&x!=fa){if(dfn[x]<low[cur])low[cur]=dfn[x];}if(vis[x]==0){cut_bridge(x,cur,dep+1);if(low[x]<low[cur])low[cur]=low[x];if(low[x]>dfn[cur])cut[cur][x]=cut[x][cur]=1;}}}int color[maxn];int tot=0;int du[maxn];void ins(int u,int v){e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}void dfs(int cur,int s){color[cur]=s;for(int i=head[cur];i;i=e[i].next){int x=e[i].to;if(cut[x][cur]==0&&color[x]==0)dfs(x,s);}}int main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;ins(x,y);ins(y,x);}cut_bridge(1,-1,0);for(int i=1;i<=n;i++){if(color[i]==0)dfs(i,++tot);}for(int i=1;i<n;i++){for(int j=i+1;j<=n;j++){if(cut[i][j]){du[color[i]]++;du[color[j]]++;}}}int num=0;for(int i=1;i<=tot;i++){if(du[i]==1)num++;}cout<<(num+1)/2<<endl;return 0;}


原创粉丝点击