Warm up HDU - 4612 树的直径
题意:给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。
题解:
你把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。然后我们可以把得到的这条链的首尾两端连起来,因为这样减少的桥最多。把所有桥减去这条链上的桥就是答案
找树的直径有两种方法,一种树形dp,一种两次dfs算法。时间复杂度都是O(n)
先说dfs:
实现:随意选取一个点作为我们的起点x,找到以x为起点的和它是最远距离的另一个端点y,然后再以y为起点找到和它是最远距离的另一个端点z,这个y->z就是树的最大直径
本题代码1就是采用的这种解法
再说树形dp:
缺点:无法找到它的直径具体路径
优点:只需一遍遍历
实现:
1 //选取任意结点为根遍历树,设dis[i]:表示结点i为根的子树结点最远距离。
2 //则有:
3 //u为根的子树结点最远距离dis[u]=max(dis[u],dis[u]+W(u-v)) v是u的子节点
4 //最后直径即为根结点的两个最远距离之和
5 int dis[maxn],len=0;
6 void DP(int u,int pre)
7 {
8 dis[u]=0; //初始为0
9 for(int i=head[u];i!=-1;i=e[i].next)
10 {
11 int v=e[i].v,w=e[i].w;
12 if(v==pre)
13 continue;
14 DP(v,u);
15 len=max(len,dis[u]+dis[v]+w); //更新直径
16 dis[u]=max(dis[u],dis[v]+w);
17 }
18 }
代码1:
1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 #include<algorithm>
5 #include<map>
6 #include<vector>
7 using namespace std;
8 const int maxn=200005;
9 vector<int>w[maxn];
10 int head[maxn],cnt,num,stacks[maxn],top,cut,in[maxn],out[maxn],pos,ci;
11 struct edge
12 {
13 int v,nnn;
14 } e[2000005];
15 int visit[maxn],belong[maxn],dfn[maxn],low[maxn];
16 void add_edge(int x,int y)
17 {
18 e[cnt].v=y;
19 e[cnt].nnn=head[x];
20 head[x]=cnt++;
21 }
22 void init()
23 {
24 memset(low,0,sizeof(low)); //这里忘记初赋值了,卧槽
25 memset(dfn,0,sizeof(dfn));
26 memset(head,-1,sizeof(head));
27 cnt=num=top=cut=ci=0;
28 pos=-1;
29 }
30 void tarjan(int x,int pre)
31 {
32 low[x]=dfn[x]=++num;
33 visit[x]=1;
34 stacks[top++]=x;
35 int flag=1;
36 for(int i=head[x]; i!=-1; i=e[i].nnn)
37 {
38 int v=e[i].v;
39 if(v==pre && flag)
40 {
41 flag=0;
42 continue;
43 }
44 if(!dfn[v])
45 {
46 tarjan(v,x);
47 low[x]=min(low[x],low[v]);
48 }
49 else if(visit[v])
50 {
51 low[x]=min(low[x],dfn[v]);
52 }
53 }
54 if(low[x]==dfn[x])
55 {
56 cut++;
57 int v;
58 while(true)
59 {
60 v=stacks[top-1];
61 top--;
62 belong[v]=cut;
63 visit[v]=0;
64 if(v==x) break;
65 //printf("*");
66 }
67 }
68 }
69 void dfs(int x,int t)
70 {
71 if(ci<t)
72 {
73 ci=t;
74 pos=x;
75 }
76 visit[x]=1;
77 int len=w[x].size();
78 for(int i=0;i<len;++i)
79 {
80 int v=w[x][i];
81 if(visit[v]) continue;
82 dfs(v,t+1);
83 }
84 }
85 int main()
86 {
87 int n,m;
88 while(~scanf("%d%d",&n,&m) && (n+m))
89 {
90 init();
91 while(m--)
92 {
93 int x,y;
94 scanf("%d%d",&x,&y);
95 add_edge(x,y);
96 add_edge(y,x);
97 }
98 tarjan(1,-1);
99 for(int i=1;i<=cut;i++)
100 w[i].clear();
101 for(int i=1;i<=n;++i)
102 {
103 for(int j=head[i];j!=-1;j=e[j].nnn)
104 {
105 int v=e[j].v;
106 int fx=belong[i];
107 int fy=belong[v];
108 if(fx!=fy)
109 {
110 w[fx].push_back(fy);
111 w[fy].push_back(fx);
112 }
113 }
114 }
115 memset(visit,0,sizeof(visit));
116 dfs(1,0);
117 memset(visit,0,sizeof(visit));
118 ci=0;
119 dfs(pos,0);
120 printf("%d\n",cut-ci-1);
121 }
122 return 0;
123 }
代码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,nnn;
24
25 }e[MAXM],edge2[MAXM];
26
27 int head[MAXN],en;
28
29 int head2[MAXN],en2;
30
31 int belong[MAXN],dfn[MAXN],low[MAXN],stacks[MAXN],top,num,scc;
32
33 int n,m;
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].nnn = 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].nnn = head2[u];
72
73 head2[u] = en2++;
74
75 }
76
77 //void tarjan(int u,int fa) //这个tarjan算法也是可以用的
78 //
79 //{
80 //
81 // dfn[u] = low[u] = ++num;
82 //
83 // stacks[++top] = u;
84 //
85 // int cnt=0;
86 //
87 // for(int i = head[u]; i != -1; i = e[i].nnn)
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 = stacks[top--];
130 //
131 // belong[x] = scc;
132 //
133 // }while(x!=u);
134 //
135 // }
136 //
137 //}
138 void tarjan(int x,int pre)
139 {
140 low[x]=dfn[x]=++num;
141 vis[x]=1;
142 stacks[top++]=x;
143 int flag=1;
144 for(int i=head[x];i!=-1;i=e[i].nnn)
145 {
146 int v=e[i].v;
147 if(v==pre && flag)
148 {
149 flag=0;
150 continue;
151 }
152 if(!dfn[v])
153 {
154 tarjan(v,x);
155 low[x]=min(low[x],low[v]);
156 }
157 else if(vis[v])
158 {
159 low[x]=min(low[x],dfn[v]);
160 }
161 }
162 if(low[x]==dfn[x])
163 {
164 scc++;
165 int v;
166 while(true)
167 {
168 v=stacks[top-1];
169 top--;
170 belong[v]=scc;
171 vis[v]=0;
172 if(v==x) break;
173 //printf("*");
174 }
175 }
176 }
177 void build()
178
179 {
180
181 en2 = 0;
182
183 memset(head2,-1,sizeof(head2));
184
185 for(int i = 1; i <= n; i++)
186
187 {
188
189 for(int j = head[i]; j!=-1; j = e[j].nnn)
190
191 {
192
193 int v = e[j].v;
194
195 if(belong[i]!=belong[v])
196
197 addedge2(belong[i],belong[v]);
198
199 }
200
201 }
202
203 }
204
205 int ans;
206
207 int dfs(int u,int p)
208
209 {
210
211 int max1=0,max2=0;
212
213 for (int i=head2[u];i!=-1;i=edge2[i].nnn)
214
215 {
216
217 int v=edge2[i].v;
218
219 if (v==p) continue;
220
221 int tmp=dfs(v,u)+1;
222
223 if (max1<tmp) max2=max1,max1=tmp;
224
225 else if (max2<tmp) max2=tmp;
226
227 }
228
229 ans=max(ans,max1+max2);
230
231 return max1;
232
233 }
234
235 int main()
236
237 {
238
239 //freopen("/home/qitaishui/code/in.txt","r",stdin);
240
241 int u,v;
242
243 while(scanf("%d%d",&n,&m)&&(n+m))
244
245 {
246
247 init();
248
249 //cout<<n<<m<<endl;
250
251 for(int i = 0; i < m; i++)
252
253 {
254
255 scanf("%d%d",&u,&v);
256
257 if (v==u) continue;
258
259 addedge(u,v);
260
261 addedge(v,u);
262
263 //cout<<u<<" "<<v<<endl;
264
265 }
266
267
268
269 tarjan(1,-1);
270
271 build();
272
273 ans=0;
274
275 dfs(1,-1);
276
277 printf("%d\n",scc-ans-1);
278
279 }
280
281 return 0;
282
283 }
Warm up HDU - 4612 树的直径的更多相关文章
- Warm up HDU - 4612( 树的直径 边双连通分量)
求在图中新建一条边后 剩下的最少的桥的数量..先tarjan求桥的数量..然后缩点..以连通分量为点建图 bfs求直径 最后用桥的数量减去直径即为答案 bfs求直径 https://www.cnb ...
- 【HDU 4612 Warm up】BCC 树的直径
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4612 题意:一个包含n个节点m条边的无向连通图(无自环,可能有重边).求添加一条边后最少剩余的桥的数 ...
- (求树的直径)Warm up -- HDU -- 4612
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之 ...
- F - Warm up - hdu 4612(缩点+求树的直径)
题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...
- F - Warm up HDU - 4612 tarjan缩点 + 树的直径 + 对tajan的再次理解
题目链接:https://vjudge.net/contest/67418#problem/F 题目大意:给你一个图,让你加一条边,使得原图中的桥尽可能的小.(谢谢梁学长的帮忙) 我对重边,tarja ...
- hdu4612 Warm up 缩点+树的直径
题意抽象后为:给定一个无向图 问添加一条边的情况下最少能有多少个桥. 桥的定义:删除该边后原图变为多个连通块. 数据规模:点数N(2<=N<=200000),边数M(1<=M< ...
- hdu 4679 树的直径
/* 题目大意:给n个点n-1条边的树,求删除哪条边时两个树中最大的直径与边权的乘积最小. 树的直径(Diameter)是指树上的最长简单路. 直径的求法:两遍BFS (or DFS) 若删除的边不是 ...
- hdu 3721 树的直径
思路:枚举+树的直径 #include<iostream> #include<cstring> #include<cstdio> #include<algor ...
- hdu 4514(树的直径+并查集)
湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Tot ...
随机推荐
- JS navigator.userAgent
var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > - ...
- 使用yaml配置文件管理资源
[root@k8s-master ~]# vim nginx-deployment.yaml apiVersion: apps/v1beta2 kind: Deployment metadata: n ...
- Jquery实现对Array数组实现类似Linq的Lambda表达式的Where方法筛选
平时使用Linq,习惯了Lambda表达式,用着非常顺手,奈何在Jquery里面不能这样用,只能循环一个个判断.趁空闲时间找了找,自己写了这样的扩展方法.目前写出了三种方案,没有比较性能,觉得都可以用 ...
- SAP中的密码输入框
在SAP中的密码输入框,可分为两种情况: 1.用selection语句书写的选择屏幕上的密码输入框 实现的方式就是在AT SELECTION-SCREEN OUTPUT事件中写入如下代码: LOOP ...
- HTTP协议相关知识整理:
http协议简介 超文本传输协议:是一种用于分布式.协作式和超媒体信息系统的应用层协议. 一次请求一次响应之后断开连接(无状态,短连接) 分析http请求信息格式 http工作原理 以下是 HTTP ...
- 处理K8S PVC删除后pod报错
报错如下 Jun 19 17:15:18 node1 kubelet[1722]: E0619 17:15:18.381558 1722 desired_state_of_world_populato ...
- Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
目录 本篇要点 什么是阻塞队列 阻塞队列提供的方法 阻塞队列的七种实现 TransferQueue和BlockingQueue的区别 1.ArrayBlockingQueue 2.LinkedBloc ...
- 全栈性能测试修炼宝典-JMeter实战笔记(二)
性能测试初体验 性能测试实质:利用工具去模拟大量用户操作来验证系统能够承受的负载情况,找出潜在的性能问题,分析并解决:找出系统性能变化趋势,为后续的扩展提供参考 测试分类 测试内容中,负载测试.压力测 ...
- Vue项目之实现登录功能的表单验证!
Vue项目之实现登录功能的表单验证! 步骤: 配置 Form表单验证; 1.必须给el-from组件绑定model 为表单数据对象 2 给需要验证的表单项 el-form-item 绑定 prop 属 ...
- 浅析Linux用户空间中的Mmap
一.MMap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.实现这样的映射关系后,进程就可以采 ...