Redundant Paths POJ - 3177

无向图概念:(这里的x->y表示x和y之间有一条无向边
1.桥:对于一个无向图,如果删除某条边后,该图的连通分量增加,则称这条边为桥

比如1->2->3->4这样一个简单得图一共有3个桥,分别是1->2,2->3,3->4

1->2->3->4->1 这样就没有桥,因为删除任意一个边,任意两点还可以互相往来(因为是双向边嘛)

2.割点/割项:对于一个无向图,如果删除某个节点u后,该图的连通分量增加,则节点u为割项或关节点

1->2->3->4 这样的图有2个割点,分别是2,3

1->2->3->4->1这样的图也是没有割点的,删除任意一个点其他点还是可以往来的

3.点-双联通:对于一个连通图,如果任意两点至少存在两条点不重复路径(即在从x走到y,如果删除任意一个其他点还可以从x走到y),
  则称这个图为点双连通(也就是通常说的的双联通) 这样的图没有割点

4.边-双联通:对于一个连通图,如果任意两点至少存在两条边不重复路径,则称该图为边双连通的

这样的图没有割边

题意:

贝西和牛群被迫从一片标着1..F的牧场走到另一片牧场,他们必须在烂苹果树附近穿过。奶牛现在已经厌倦了经常被迫走一条特定的路,想要建一些新的路,这样它们就可以在任何一对田地之间至少有两条不同的路可选。他们目前在每对字段之间至少有一条路由,并且希望至少有两条路由。

题解:

那我们可以把所有割边都消除了就可以了

我们通过看图可以发现,割边一般是存在在一个点只与其他所有点有且仅有一条无向边

因为题目上已经保证了任意两点之间至少有一条路,所有我们找到所有这样的点,让它们互相连起来就可以了

黑边是原图的,红边是添加后使图变成边-双连通图的

根据上面描述,2,3,4都属于这样的点,我们就需要2条边就可以使它变成双连通图

根据上面描述,2,3,4,5都属于这样的点,我们就需要2条边就可以使它变成双连通图

这样的话,任意一个点到达其他点至少有两条路径

代码1:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<map>
 6 using namespace std;
 7 const int maxn=5010;
 8 int head[maxn],cnt,num,stacks[maxn],top,cut,in[maxn],out[maxn];
 9 struct edge
10 {
11     int v,next;
12 }e[maxn];
13 int visit[maxn],belong[maxn],dfn[maxn],low[maxn];
14 void add_edge(int x,int y)
15 {
16     e[cnt].v=y;
17     e[cnt].next=head[x];
18     head[x]=cnt++;
19 }
20 void init()
21 {
22     memset(in,0,sizeof(in));
23     memset(out,0,sizeof(out));
24     memset(head,-1,sizeof(head));
25     cnt=num=top=cut=0;
26 }
27 void tarjan(int x,int pre)
28 {
29     low[x]=dfn[x]=++num;
30     visit[x]=1;
31     stacks[top++]=x;
32     int flag=1;
33     for(int i=head[x];i!=-1;i=e[i].next)
34     {
35         int v=e[i].v;
36         if(v==pre && flag)
37         {
38             flag=0;
39             continue;
40         }
41         if(!dfn[v])
42         {
43             tarjan(v,x);
44             low[x]=min(low[x],low[v]);
45         }
46         else if(visit[v])
47         {
48             low[x]=min(low[x],dfn[v]);
49         }
50     }
51     if(low[x]==dfn[x])
52     {
53         cut++;
54         int v;
55         while(true)
56         {
57             v=stacks[top-1];
58             top--;
59             belong[v]=cut;
60             visit[v]=0;
61             if(v==x) break;
62             //printf("*");
63         }
64     }
65 }
66 int main()
67 {
68     int n,m;
69     init();
70     scanf("%d%d",&n,&m);
71     while(m--)
72     {
73         int x,y;
74         scanf("%d%d",&x,&y);
75         add_edge(x,y);
76         add_edge(y,x);
77     }
78     tarjan(1,-1);
79     //printf("**\n");
80     for(int i=1;i<=n;++i)
81     {
82         for(int j=head[i];j!=-1;j=e[j].next)
83         {
84             int v=e[j].v;
85             if(belong[i]!=belong[v])
86             {
87                 in[belong[v]]++;
88                 out[belong[i]]++;
89             }
90         }
91     }
92     int ans=0;
93     for(int i=1;i<=n;++i)
94     {
95         if(out[i]==1)
96             ans++;
97     }
98     printf("%d\n",(ans+1)/2);
99 }

代码2:

  1 //time 1031MS
  2
  3 //memory 31340K
  4
  5 #pragma comment(linker, "/STACK:1024000000,1024000000")
  6
  7 #include <iostream>
  8
  9 #include <cstdio>
 10
 11 #include <cstdlib>
 12
 13 #include <cstring>
 14
 15 #define MAXN 300015
 16
 17 #define MAXM 4000015
 18
 19 using namespace std;
 20
 21 struct Edge{
 22
 23     int v,next;
 24
 25 }e[MAXM];
 26
 27 int head[MAXN],en;
 28
 29 int head2[MAXN],en2;
 30
 31 int belong[MAXN],dfn[MAXN],low[MAXN],sta[MAXN],top,num,scc;
 32
 33 int in[MAXN],out[MAXN];
 34
 35 bool vis[MAXN];
 36
 37 void init()
 38
 39 {
 40
 41     memset(head,-1,sizeof(head));
 42
 43     memset(vis,0,sizeof(vis));
 44
 45     en = 0;
 46
 47     top = 0;
 48
 49     scc=num = 0;memset(dfn,0,sizeof(dfn));
 50
 51 }
 52
 53 void addedge(int u,int v)
 54
 55 {
 56
 57     e[en].v = v;
 58
 59     e[en].next = head[u];
 60
 61     head[u] = en++;
 62
 63 }
 64
 65 //void addedge2(int u,int v)
 66 //
 67 //{
 68 //
 69 //    edge2[en2].v = v;
 70 //
 71 //    edge2[en2].next = head2[u];
 72 //
 73 //    head2[u] = en2++;
 74 //
 75 //}
 76
 77 void tarjan(int u,int fa)
 78
 79 {
 80
 81     dfn[u] = low[u] = ++num;
 82
 83     sta[++top] = u;
 84
 85     int cnt=0;
 86
 87     for(int i = head[u]; i != -1; i = e[i].next)
 88
 89     {
 90
 91         int v = e[i].v;
 92
 93         if(!dfn[v])
 94
 95         {
 96
 97             tarjan(v,u);
 98
 99             low[u] = min(low[u],low[v]);
100
101         }
102
103         else if (fa==v)
104
105         {
106
107             if (cnt) low[u] = min(low[u],dfn[v]);//重边
108
109             cnt++;
110
111         }
112
113         else low[u] = min(low[u],dfn[v]);
114
115     }
116
117     if(dfn[u]==low[u])
118
119     {
120
121         int x;
122
123         scc++;
124
125         do
126
127         {
128
129             x = sta[top--];
130
131             belong[x] = scc;
132
133         }while(x!=u);
134
135     }
136
137 }
138
139 //void build()
140 //
141 //{
142 //
143 //    en2 = 0;
144 //
145 //    memset(head2,-1,sizeof(head2));
146 //
147 //    for(int i = 1; i <= n; i++)
148 //
149 //    {
150 //
151 //        for(int j = head[i]; j!=-1; j = e[j].next)
152 //
153 //        {
154 //
155 //            int v = e[j].v;
156 //
157 //            if(belong[i]!=belong[v])
158 //
159 //                addedge2(belong[i],belong[v]);
160 //
161 //        }
162 //
163 //    }
164 //
165 //}
166
167 int ans;
168
169 //int dfs(int u,int p)
170 //
171 //{
172 //
173 //    int max1=0,max2=0;
174 //
175 //    for (int i=head2[u];i!=-1;i=edge2[i].next)
176 //
177 //    {
178 //
179 //        int v=edge2[i].v;
180 //
181 //        if (v==p) continue;
182 //
183 //        int tmp=dfs(v,u)+1;
184 //
185 //        if (max1<tmp) max2=max1,max1=tmp;
186 //
187 //        else if (max2<tmp) max2=tmp;
188 //
189 //    }
190 //
191 //    ans=max(ans,max1+max2);
192 //
193 //    return max1;
194 //
195 //}
196 int main()
197 {
198     int n,m;
199     init();
200     scanf("%d%d",&n,&m);
201     while(m--)
202     {
203         int x,y;
204         scanf("%d%d",&x,&y);
205         addedge(x,y);
206         addedge(y,x);
207     }
208     tarjan(1,-1);
209     //printf("**\n");
210     for(int i=1;i<=n;++i)
211     {
212         for(int j=head[i];j!=-1;j=e[j].next)
213         {
214             int v=e[j].v;
215             if(belong[i]!=belong[v])
216             {
217                 in[belong[v]]++;
218                 out[belong[i]]++;
219             }
220         }
221     }
222     int ans=0;
223     for(int i=1;i<=n;++i)
224     {
225         if(out[i]==1)
226             ans++;
227     }
228     printf("%d\n",(ans+1)/2);
229 }
230 //int main()
231 //
232 //{
233 //
234 //    //freopen("/home/qitaishui/code/in.txt","r",stdin);
235 //
236 //    int u,v;
237 //
238 //    while(scanf("%d%d",&n,&m)&&(n+m))
239 //
240 //    {
241 //
242 //        init();
243 //
244 //        //cout<<n<<m<<endl;
245 //
246 //        for(int i = 0; i < m; i++)
247 //
248 //        {
249 //
250 //            scanf("%d%d",&u,&v);
251 //
252 //            if (v==u) continue;
253 //
254 //            addedge(u,v);
255 //
256 //            addedge(v,u);
257 //
258 //            //cout<<u<<" "<<v<<endl;
259 //
260 //        }
261 //
262 //
263 //
264 //        tarjan(1,-1);
265 //
266 //        build();
267 //
268 //        ans=0;
269 //
270 //        dfs(1,-1);
271 //
272 //        printf("%d\n",scc-ans-1);
273 //
274 //    }
275 //
276 //    return 0;
277 //
278 //}

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11664054.html

时间: 2024-10-09 21:42:31

Redundant Paths POJ - 3177的相关文章

Redundant Paths POJ - 3177(边双连通)

Redundant Paths POJ - 3177 题意:一个无向图(有重边!!),问至少还要加多少边使得去掉任意一条边后任意两点仍可互达. 和上题poj3352基本相同,不过dfs的时候,不能用v!=f来判断是否能走,而要用当前走的边和上一条边是不是反向边 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namesp

E - Redundant Paths - poj 3177(缩点求叶子节点)

题意:给一个图,想让每两条路都有两条边相,不过特殊的是相同的边多次相连也被认为是一条边,现在求最少还需要添加几条边才能做到 分析:手欠没看清楚是相同的边不能相连,需要去重边,缩点后求出来叶子节点的数目即可. *********************************************************************** #include<stdio.h>#include<string.h>#include<algorithm>using n

Redundant Paths POJ - 3177(边—双连通分量)

题意: 在图中加边 看最少能通过加多少条边把 图变成边-双连通分量 解析: 先做一次dfs,不同的连通分量的low是不同的  注意重边 缩点 统计度为1的点  那么需要加的边为(ret+1)/2 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include

POJ 3177 Redundant Paths POJ 3352 Road Construction(双连通)

POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的,一份代码能交,给定一个连通无向图,问加几条边能使得图变成一个双连通图 思路:先求双连通,缩点后,计算入度为1的个数,然后(个数 + 1) / 2 就是答案(这题由于是只有一个连通块所以可以这么搞,如果有多个,就不能这样搞了) 代码: #include <cstdio> #include <cstring> #include <algorithm&

poj 3177 Redundant Paths (双联通)

/******************************************************* 题目:Redundant Paths (poj 2177) 链接:http://poj.org/problem?id=3177 算法:双联通+缩点 思路:先找出所有双联通分量,把这些分量缩成一个点 再找出所有度为一的点,用这些点数加一除2就可以了 ********************************************************/ #include<cs

tarjan算法求桥双连通分量 POJ 3177 Redundant Paths

POJ 3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12598   Accepted: 5330 Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the re

poj 3177 Redundant Paths

Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forc

POJ 3177 Redundant Paths(Tarjan)

题目链接 题意 : 一个无向连通图,最少添加几条边使其成为一个边连通分量 . 思路 :先用Tarjan缩点,缩点之后的图一定是一棵树,边连通度为1.然后找到所有叶子节点,即度数为1的节点的个数leaf,最后要添加的边的条数就是(leaf+1)/2 : 1 // 3177 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 7 using

POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点)

POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点) ACM 题目地址: POJ 3352 Road Construction POJ 3177 Redundant Paths 题意: 问要添加几条边才能使所给无向图图变成边双连通图. 分析: 边连通度:使无向图G不连通的最少删边数量为其边连通度. 边双连通图:边连通度大于1的无向图. 首先缩点,让图变成一个DAG. 现在问题转化为:在树中至少添加多少条边能使图变