本文主要是介绍poj 3117poj 3352 (边双连通分量+缩点 Tarjan算法 ),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。
缩点后,新图是一棵树,树的边就是原无向图的桥。
现在问题转化为:在树中至少添加多少条边能使图变为双连通图。
结论:添加边数=(树中度为1的节点数+1)/2
具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。
缩点之后形成一棵树 求出叶子节点的数量(图中度为1的点)ps:两题ac的代码一样
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)using namespace std;void read(int &x)
{char ch;x=0;while(ch=getchar(),ch!=' '&&ch!='\n'){x=x*10+ch-'0';}
}const int MAXN=5010;
const int MAXM=10010;
struct Edge
{int to,next;
}edge[2*MAXM];
int head[MAXN],tot;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN];//belong数组的值是1~scc
int index,top;
int scc; //强连通分量的个数
bool instack[MAXN];
int num[MAXN];//各个强连通分量包含点个数 数组编号1~scc
//num数组不一定需要 结合实际情况
int degree[MAXN];void addedge(int u,int v)
{edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++;
}void Tarjan(int u,int fa)
{low[u]=dfn[u]=++index;stack[++top]=u;instack[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(i==(fa^1)) continue;if(!dfn[v]){Tarjan(v,i);low[u]=min(low[u],low[v]);}else if(instack[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){scc++;while(1){int v=stack[top--];instack[v]=0;belong[v]=scc;if(v==u)break;}}
}int main()
{
// fread;int n,m;while(scanf("%d%d",&n,&m)!=EOF){tot=index=top=scc=0;MEM(head,-1);MEM(low,0);MEM(dfn,0);MEM(instack,0);MEM(degree,0);for(int i=0;i<m;i++){int u,v;scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(1,-1);for(int i=1;i<=n;i++){for(int j=head[i];j!=-1;j=edge[j].next){int v=edge[j].to;if(belong[i]!=belong[v])degree[belong[i]]++;}}int sum=0;for(int i=1;i<=n;i++)if(degree[i]==1)sum++;int ans=(sum+1)/2;printf("%d\n",ans);}return 0;
}
这篇关于poj 3117poj 3352 (边双连通分量+缩点 Tarjan算法 )的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!