树形dp题集之树的直径
2015-11-06 22:29
375 查看
前言:
所谓的树的直径就是树上两点之间的最大距离
求树的直径有三种方法,三种方法详解
【codeforces 592D】
这一题写过博客的点击打开链接
【POJ 1985 Cow Marathon】
给你一棵树,求树上的两个点之间的最大的距离
先假设1是树的跟,从1开始,一次搜索,求出跟1距离最大的点,记为di
假设di是树的跟,再搜索一次,求出答案
【HDU 2196 Computer】
给你一棵树,求树上一点到树上的另一个点最远的距离
这棵树是没有根的
我假设1是整棵树的根节点
第一次dfs求出每个节点到1的距离,记为dis[ i ],求的时候将1的每一棵子树都用相应的数字标记
同时,求出跟1距离最大,第二大的两个子树,距离记为max1, max2,跟1最远的那个点记为d1
然后以d1为根节点,再扫一次,树上每一个点跟d1的距离记为dis2[ i ]
距离最大的子树上的点到树上另一个点最大距离就是max(dis2[ i ], max2 + dis[i])
其它的点 i 到树上另一个点的最大距离就是max(dis2[ i ], max1 + dis[ i ])
注意max1, max2不能在同一棵树上
【POJ 1383 Labyrinth】
在n*m的方阵中,'#'表示不能走过,'.'表示通路
求方阵中'.'最长是多少
先用bfd处理处相连的两个点
然后两次dfs求出这个联通快的最长距离
所谓的树的直径就是树上两点之间的最大距离
求树的直径有三种方法,三种方法详解
【codeforces 592D】
这一题写过博客的点击打开链接
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">#include <bits/stdc++.h> using namespace std; #define inf 130000 vector<int>adj[inf]; int vis[inf]; int sizee[inf], dis[inf]; void dfs(int p, int u) { sizee[u] = 0; if(vis[u]) sizee[u]=1; for(int i = 0; i < adj[u].size(); i++) { int v = adj[u][i]; if(v!=p) { dis[v] = dis[u] + 1; dfs(u, v); sizee[u] += sizee[v]; } } } int main() { int n, m; scanf("%d%d", &n, &m); for(int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); adj[u].push_back(v); adj[v].push_back(u); } memset(vis, 0, sizeof(vis)); for(int i = 0; i < m; i++) { int a; scanf("%d", &a); vis[a] = 1; } memset(dis, 0, sizeof(dis)); dfs(-1, 1); int v = -1; for(int i = 1; i <= n; i++) { if(vis[i] && (v==-1 || dis[i] > dis[v])) v = i; } memset(dis, 0, sizeof(dis)); dfs(-1, v); int sum = 0, sx = 0; for(int i = 1; i <= n; i++) { if(sizee[i] && m-sizee[i]>0) sum += 2; if(vis[i]) sx = max(sx, dis[i]); } for(int i = 1; i <= n; i++) { if(sx==dis[i] && vis[i] && i<v) v = i; } printf("%d\n%d\n", v, sum-sx); return 0; } </span></span></span>
【POJ 1985 Cow Marathon】
给你一棵树,求树上的两个点之间的最大的距离
先假设1是树的跟,从1开始,一次搜索,求出跟1距离最大的点,记为di
假设di是树的跟,再搜索一次,求出答案
<span style="font-size:14px;"><span style="font-size:14px;">#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <vector> using namespace std; int dis[40005], maxn, di; struct node { int id, len; }; vector<node>vec[40005]; void dfs(int p, int u) { for(int i = 0; i < vec[u].size(); i++) { node v = vec[u][i]; if(p != v.id) { dis[v.id] = dis[u] + v.len; if(maxn < dis[v.id]) { maxn = dis[v.id]; di = v.id; } dfs(u, v.id); } } } int main() { int n, m; while(~scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; i++) vec[i].clear(); for(int i = 0; i < m; i++) { node p; char c[5]; int u, v, li; scanf("%d%d%d%s", &u, &v, &li, c); p.id = u, p.len = li; vec[v].push_back(p); p.id = v; vec[u].push_back(p); } memset(dis, 0, sizeof(dis)); maxn = -1; dfs(-1, 1); memset(dis, 0, sizeof(dis)); dfs(-1, di); printf("%d\n", maxn); } return 0; }</span></span>
【HDU 2196 Computer】
给你一棵树,求树上一点到树上的另一个点最远的距离
这棵树是没有根的
我假设1是整棵树的根节点
第一次dfs求出每个节点到1的距离,记为dis[ i ],求的时候将1的每一棵子树都用相应的数字标记
同时,求出跟1距离最大,第二大的两个子树,距离记为max1, max2,跟1最远的那个点记为d1
然后以d1为根节点,再扫一次,树上每一个点跟d1的距离记为dis2[ i ]
距离最大的子树上的点到树上另一个点最大距离就是max(dis2[ i ], max2 + dis[i])
其它的点 i 到树上另一个点的最大距离就是max(dis2[ i ], max1 + dis[ i ])
注意max1, max2不能在同一棵树上
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <string> #include <vector> using namespace std; #define ll __int64 int vis[10005]; ll dis[10005], dis2[10005]; ll max1, max2; int d1, di; struct node { int id, len; }; vector<node>vec[10005]; void dfs(int p, int u, int li) { for(int i = 0; i < vec[u].size(); i++) { node v = vec[u][i]; if(v.id != p) { dis[v.id] = dis[u]+(ll)v.len; if(max1 < dis[v.id]) { if(d1 == li) { max1 = dis[v.id]; di = v.id; } else { max2 = max1; max1 = dis[v.id]; d1 = li; di = v.id; } } else if(max1 >= dis[v.id] && max2 < dis[v.id] && d1 != li) { max2 = dis[v.id]; } vis[v.id] = li; dfs(u, v.id, li); } } } void dfs2(int p, int u) { for(int i = 0; i < vec[u].size(); i++) { node v = vec[u][i]; if(v.id != p) { dis2[v.id] = dis2[u] + (ll)v.len; dfs2(u, v.id); } } } int main() { int n; while(~scanf("%d", &n)) { if(n == 0) break; if(n == 1) { printf("0\n"); continue; } for(int i = 1; i <= n; i++) vec[i].clear(); for(int i = 2; i <= n; i++) { node p; scanf("%d%d", &p.id, &p.len); int d = p.id; vec[i].push_back(p); p.id = i; vec[d].push_back(p); } memset(dis, 0, sizeof(dis)); memset(vis, 0, sizeof(vis)); max1 = max2 = 0; d1 = 0; for(int i = 0; i < vec[1].size(); i++) { node v = vec[1][i]; dis[v.id] = (ll)v.len; if(max1 < dis[v.id]) { max2 = max1; max1 = dis[v.id]; d1 = i+1; di = v.id; } else if(max1 >= dis[v.id] && max2 < dis[v.id] && d1 != i+1) { max2 = dis[v.id]; } vis[v.id] = i+1; dfs(1, v.id, i+1); } memset(dis2, 0, sizeof(dis2)); dfs2(-1, di); for(int i = 1; i <= n; i++) { if(vis[i] == d1) printf("%I64d\n", max(dis2[i], dis[i]+max2)); else printf("%I64d\n", max(dis2[i], dis[i]+max1)); } } return 0; }
【POJ 1383 Labyrinth】
在n*m的方阵中,'#'表示不能走过,'.'表示通路
求方阵中'.'最长是多少
先用bfd处理处相连的两个点
然后两次dfs求出这个联通快的最长距离
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <vector> using namespace std; #define inf 1000005 char s[1005][1005]; int vis[1005][1005], f[4][2] = {0,1, 1,0, 0,-1, -1,0}; int li, n, m, tol; int head[inf]; int dis[inf], maxn, id; struct Edge { int to, next; }edge[inf*2]; struct node { int x, y; }; bool is_ok(int x, int y) { if(x<m && x>=0 && y<n && y>=0) return true; return false; } void dfs(int p, int u) { for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(p != v) { dis[v] = dis[u] + 1; if(maxn < dis[v]) { maxn = dis[v]; id = v; } dfs(u, v); } } } void add(int a, int b) { edge[tol].to = b; edge[tol].next = head[a]; head[a] = tol++; } void bfs(int x, int y) { int k = li; queue<node>q; node s, e; s.x = x, s.y = y; q.push(s); while(!q.empty()) { s = q.front(); q.pop(); for(int i = 0; i < 4; i++) { e = s; e.x += f[i][0]; e.y += f[i][1]; if(is_ok(e.x, e.y)) { if(vis[e.x][e.y] == -1) { li++; vis[e.x][e.y] = li; q.push(e); } if(vis[e.x][e.y] > 0) { add(vis[s.x][s.y], vis[e.x][e.y]); } } } } memset(dis, 0, sizeof(dis)); maxn = -1; dfs(-1, k); memset(dis, 0, sizeof(dis)); dfs(-1, id); } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) { scanf("%s", s[i]); for(int j = 0; j < n; j++) { if(s[i][j] == '#') vis[i][j] = 0; else vis[i][j] = -1; } } int Max = 0; for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { if(vis[i][j] == -1) { li=1, tol = 0; memset(head, -1, sizeof(head)); vis[i][j] = li; bfs(i, j); Max = max(Max, maxn); } } } printf("Maximum rope length is %d.\n", Max); } return 0; }
相关文章推荐
- LightOJ - 1048 Conquering Keokradong(贪心)
- fastdfs环境搭建
- 14 Longest Common Prefix
- ScrollView 获取滑动方向
- CentOS 中安装和卸载 Emacs
- FMDB总结及其中的一些注意点
- 排序算法(二):希尔排序
- cocos2d-x设计模式发掘之一:单例模式
- Angular.JS + Require.JS + angular-async-loader 来实现异步加载 angular 模块
- 关于java初学者的心理
- Turn the corner
- 53. PHP 伪静态(2)
- C++的面向对象的Dijkstra写法
- Caffe cuDNN max-pooling with in-place dropout
- mysql向表中插入时间
- android AsyncTask介绍
- java基本数据类型
- 简单 实现CombineFileInputFormat
- 深度理解依赖注入(Dependence Injection)
- [Android基础]BroadcastReceiver