pku 3711 Redundant Paths

双连通分量。

题目大意:给出一个连通图,求至少添加多少条边,使得对于任意亮点,不只一条路。即两点间的路去掉一条边还是连通的。

思路:用双联通缩点,然后求出度为一的双连通分量的个数count1,最后(count1+1)/2即是所求!!

这个题基本上算是我接触双连通的第一道题,写了好多个版本,最后还是稍微了理解了一些双联通。。

双连通分量的tarjan用不用栈都可以,因为它不会存在横向边,不需要考虑下一个点是否在栈中。。

 if(low[u]==dfn[u])
{
count++;
do{
v=S.top();
S.pop();
vis[v]=0;
Belong[v]=count;
}while(v!=u);
}
用栈的话可以很明显的看出有几个双连通分量(即count),然后某一个点属于某一个双连通分量也很清楚!

void tarjan(int u,int father)
{
 int j,v;
 dfn[u]=low[u]=cnt++;
 visit[u]=1;
 for(j=head[u];j!=-1;j=edge[j].next)
 {
  v=edge[j].to;
  if(v==father) continue;
  if(!visit[v]) tarjan(v,u);
  low[u]=min(low[u],low[v]);
 }
}

不用栈的话low[i]即是指i所在的双联通分量,比较简洁,不用开很多数组!

对这道题而言,需要去掉重边。

贴一个比较简洁一点的代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 1 # include<stdio.h>
2 # include<string.h>
3 # define N 5005
4 struct node{
5 int from,to,next;
6 }edge[N*4];
7 //bool adj[N][N];
8 int tol,head[N],visit[N],dfn[N],low[N],n,m,cnt,degree[N];
9 void add(int a,int b)
10 {
11 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
12 }
13 int min(int a,int b)
14 {
15 return a<b?a:b;
16 }
17 void tarjan(int u,int father)
18 {
19 int j,v;
20 dfn[u]=low[u]=cnt++;
21 visit[u]=1;
22 for(j=head[u];j!=-1;j=edge[j].next)
23 {
24 v=edge[j].to;
25 if(v==father) continue;
26 if(!visit[v]) tarjan(v,u);
27 low[u]=min(low[u],low[v]);
28 }
29 }
30 int judge(int a,int b)//判断是否出现重边
31 {
32 int j;
33 for(j=head[a];j!=-1;j=edge[j].next)
34 {
35 if(b==edge[j].to) return 0;
36 }
37 return 1;
38 }
39 int main()
40 {
41 int i,count1,a,b;
42 while(scanf("%d%d",&n,&m)!=EOF)
43 {
44 tol=cnt=0;
45 memset(head,-1,sizeof(head));
46 //memset(adj,0,sizeof(adj));
47 for(i=1;i<=m;i++)
48 {
49 scanf("%d%d",&a,&b);
50 if(judge(a,b))
51 {
52 add(a,b);
53 add(b,a);
54 }
55 }
56 memset(visit,0,sizeof(visit));
57 tarjan(1,0);
58 memset(degree,0,sizeof(degree));
59 for(i=0;i<tol;i++)
60 {
61 a=edge[i].from;
62 b=edge[i].to;
63 if(low[a]!=low[b]) degree[low[b]]++;
64 }
65 count1=0;
66 for(i=0;i<cnt;i++)
67 if(degree[i]==1) count1++;
68 printf("%d\n",(count1+1)/2);
69 }
70 return 0;
71 }

转载于:https://www.cnblogs.com/183zyz/archive/2011/08/02/2124730.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值