首页 > 学院 > 开发设计 > 正文

POJ 3177(双连通分量 有重边)

2019-11-06 09:11:46
字体:
来源:转载
供稿:网友

POJ 3177

题目大意

题目和3352基本一样,只是多了可能有重边这个条件

分析

题目分析见POJ 3352 Road Construction(边双连通) 重边的处理我在tarjan算法中用了一个flag标记,从儿子v开始搜索搜到父亲u,此时如果flag为0表示这是树枝边(就是从u搜到v的边)跳过,为1表示已经处理过树枝边了说明这是一条重边。

总结

应该是这道题数据太水了,直接把重边去掉也能AC

2 2 1 2 1 2

对于这组数据,去重边的方法得出的答案是1,而正确答案应该是0

代码

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>#include<map>#include<algorithm>#include<set>#include<stack>using namespace std;const int MAXN=1005;int bj[MAXN][MAXN];struct node //前向星实现{ int v; int next;}edge[10005];int edgecount;int head[MAXN];int ti=0;//时间int dfn[MAXN];int low[MAXN];int vis[MAXN];int belong[MAXN];int de[MAXN];int n,m;int cnt;void Add_edge(int u,int v){ edge[++edgecount].v=v; edge[edgecount].next=head[u]; head[u]=edgecount;}void Init(){ memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(de,0,sizeof(de)); edgecount=0; ti=0; cnt=0;}stack<int> St;void Tarjan(int p,int u){ dfn[u]=low[u]=++ti; St.push(u); vis[u]=1; int flag=0; for(int k=head[u];k!=-1;k=edge[k].next) { int v=edge[k].v; if(v==p && flag==0){flag=1;continue;} if(!dfn[v]) { Tarjan(u,v); low[u]=min(low[u],low[v]); } else// if(vis[v]==1)//v在栈中,说明(u,v)是返祖边 low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u])//将u所在的边连通分量出栈 { int x; ++cnt;//cnt表示缩点后的连通分量 while(1) { x=St.top(); St.pop(); vis[x]=0; belong[x]=cnt; if(x==u)break; } }}void Solve(){ for(int i=1;i<=n;i++) { if(dfn[i]==0)Tarjan(0,i); } for(int u=1;u<=n;u++) { for(int k=head[u];k!=-1;k=edge[k].next) { int v=edge[k].v; if(belong[u]!=belong[v]) de[belong[u]]++; } } int ans=0; for(int i=1;i<=cnt;i++) { if(de[i]==1)ans++; } ans=(ans+1)/2; cout<<ans<<endl;}int main(){ int a,b; while(scanf("%d%d",&n,&m)!=EOF) { Init(); memset(bj,0,sizeof(bj)); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); //if(bj[a][b]==1)continue; //bj[a][b]=bj[b][a]=1; Add_edge(a,b); Add_edge(b,a); } Solve(); } return 0;}/*2 21 21 2*/
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表