poj3352 Road Construction 边双连通分量tarjan算法
2017-10-03 21:21
369 查看
http://poj.org/problem?id=3352
题意:有n个城市m条道路,一开始任何两个城市相互可达。现在需要某条修路,修路时该道路不可通行。然后需要搭建临时的桥,使得任何两个城市仍是相互可达的。求最少需要搭建的桥的数量。
题解:这是一个无向图,去掉一条边就不连通。那么这条边就是桥。现在要搭建临时的桥,搭建完后与原图一起,这个有向图就是边双连通的(边连通度大于1)。现在就是求加上几条边使得这个无向图是边双连通的。
首先tarjan求出边双连通分量,对边双连通分量进行缩点,那么就形成一棵树。
然后就是对于一棵树,如何加边使得它边双连通,有一个结论:加边数=(叶子节点数+1)/2。即加边后无度数为1的点。
代码:
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 1000 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int head
,len;
int dfn
,low
,dfs_num;//dfn表示遍历深度,low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int deg
,ans;
struct EdgeNode{
int to,next;
}edge
;
void add(int i,int j){
edge[len].to=j;
edge[len].next=head[i];
head[i]=len++;
}
void init(){
mem(deg,0),mem(dfn,0),mem(low,0),mem(head,-1),ans=len=dfs_num=0;
}
void tarjan(int x,int from){
dfn[x]=low[x]=++dfs_num;
for(int i=head[x];i!=-1;i=edge[i].next){
int temp=edge[i].to;
if(temp==from) continue;
if(!dfn[temp]){
tarjan(temp,x);
low[x]=min(low[x],low[temp]);
}
else{
low[x]=min(dfn[temp],low[x]);
}
}
}
void solve(int n){
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i,-1);
}
}
for(int i=1;i<=n;i++){
for(int k=head[i];k!=-1;k=edge[k].next){
int temp=edge[k].to;
//不属于同一个边连通分量
if(low[i]!=low[temp]){
deg[low[i]]++;
}
}
}
//这里的i表示low[]
for(int i=1;i<=n;i++){
if(deg[i]==1){
ans++;
}
}
ans=(ans+1)/2;
}
int main(){
int n,m,u,v;
char a;
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
solve(n);
printf("%d\n",ans);
}
return 0;
}
题意:有n个城市m条道路,一开始任何两个城市相互可达。现在需要某条修路,修路时该道路不可通行。然后需要搭建临时的桥,使得任何两个城市仍是相互可达的。求最少需要搭建的桥的数量。
题解:这是一个无向图,去掉一条边就不连通。那么这条边就是桥。现在要搭建临时的桥,搭建完后与原图一起,这个有向图就是边双连通的(边连通度大于1)。现在就是求加上几条边使得这个无向图是边双连通的。
首先tarjan求出边双连通分量,对边双连通分量进行缩点,那么就形成一棵树。
然后就是对于一棵树,如何加边使得它边双连通,有一个结论:加边数=(叶子节点数+1)/2。即加边后无度数为1的点。
代码:
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 1000 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int head
,len;
int dfn
,low
,dfs_num;//dfn表示遍历深度,low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int deg
,ans;
struct EdgeNode{
int to,next;
}edge
;
void add(int i,int j){
edge[len].to=j;
edge[len].next=head[i];
head[i]=len++;
}
void init(){
mem(deg,0),mem(dfn,0),mem(low,0),mem(head,-1),ans=len=dfs_num=0;
}
void tarjan(int x,int from){
dfn[x]=low[x]=++dfs_num;
for(int i=head[x];i!=-1;i=edge[i].next){
int temp=edge[i].to;
if(temp==from) continue;
if(!dfn[temp]){
tarjan(temp,x);
low[x]=min(low[x],low[temp]);
}
else{
low[x]=min(dfn[temp],low[x]);
}
}
}
void solve(int n){
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i,-1);
}
}
for(int i=1;i<=n;i++){
for(int k=head[i];k!=-1;k=edge[k].next){
int temp=edge[k].to;
//不属于同一个边连通分量
if(low[i]!=low[temp]){
deg[low[i]]++;
}
}
}
//这里的i表示low[]
for(int i=1;i<=n;i++){
if(deg[i]==1){
ans++;
}
}
ans=(ans+1)/2;
}
int main(){
int n,m,u,v;
char a;
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
solve(n);
printf("%d\n",ans);
}
return 0;
}
相关文章推荐
- 【POJ3352】Road Construction tarjan求边-双连通分量,裸题模板题
- POJ 3352 Road Construction(双连通分量Tarjan算法)
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
- Road Construction 求双连通分量(tarjan)缩点,最后求度为1的点的个数cnt,则所需要增加的边(cnt+1)/2
- POJ 3352 Road Construction(边双连通分量,桥,tarjan)
- 边双联通问题求解(构造边双连通图)POJ3352(Road Construction)
- POJ 3352 Road Construction【双连通分量_桥】
- POJ 3352 Road Construction (边双连通分量)
- poj 3352 Road Construction 边双连通分量
- 【POJ3352】Road Construction(边双联通分量)
- POJ 3352 Road Construction (边双连通分量 Tarjan缩点)
- POJ - 3352 Road Construction(边双连通分量)
- poj3352 Road Construction 缩点
- POJ 3352 Road Construction 构造双连通分量 && POJ 3177Redundant Paths注意重边
- POJ---3352-Road Construction(双连通分量)
- poj 3352 Road Construction(边-双连通分量)
- Road Construction POJ - 3352 (边双连通分量)题解
- poj3352——Road Construction(双连通分量)
- POJ-3352 Road Construction 双连通分量
- POJ 3352 Road Construction (边双连通分量)