最长直径有几个
来源:互联网 发布:office数据库教程 编辑:程序博客网 时间:2024/04/27 15:32
HDU - 3534
题目描述:
给出一棵树,问最长的直径是多少,并且问个数
题解:
树形dp,关键这一次要计算个数.dp[u]表示长度,num[u]表示个数.那么往根u推的时候,要搞出:两条链分别是u的两个儿子上的和的最大值以及它的个数.这个需要:这样一定要是用动态规划来扫一遍算,枚举当前边是第二条边的话怎么怎么样.如果不是横着扫,会出很多问题,因为情况可以相交的和不可以相交的都统计在一块是不对的,因此一定一定要用dp横着扫啊啊啊.之后就是怎么搞出选择v这个儿子之后取出所有的v的往下走的最大值和它的个数.这个才是真正的dp,max_l[v]和max_n[v]代表从v发出的所有的不同路径的总和,不管相交不相交.这样这道题就结束了
重点:
关键是区分开两个东西:找u点且涉及u点的直径时,需要两条链不相交,就是说一个链在一个儿子,另一个链在另一个儿子,并且需要保证这两个的和是最大的,而且有很多长度重复的情况要考虑,这样的话必须用动态规划横着扫是最好的.另一个:以u为出发点往下走的长度最大值和所有不同路径的个数.这个要求不同路径的个数,不需要从一开始区分是哪两个儿子,因此全部无脑统计在一起就好了.
代码:
//代码的alll是所有无脑统计在一起的u发出的不同路径的最大长度//第二个dfs会用到dpm和dps,其实,如果直接横着扫过去是用不着这两个东西的//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e5 + 10;int n, dpm[maxn], dps[maxn], num_m[maxn], num_s[maxn];int alll[maxn], alln[maxn];int l[maxn], numl[maxn];int ans, ans_n;struct info{ int to, len;};vector<info> G[maxn];void dfs(int u, int fa){ dpm[u] = 0; alll[u] = 0; alln[u] = 1; dps[u] = 0; num_m[u] = num_s[u] = 1; REP(i, 0, G[u].size()) { int v = G[u][i].to, len = G[u][i].len; if(v!=fa) { dfs(v, u); int tmp = alll[v]+len; if(tmp > alll[u]) { alll[u] = tmp; alln[u] = alln[v]; } else if(tmp == alll[u]) { alln[u] += alln[v]; } if(tmp>dpm[u]) { dps[u] = dpm[u]; num_s[u] = num_m[u]; dpm[u] = tmp; num_m[u] = alln[v]; } else if(tmp == dpm[u]&&alln[v] > num_m[u]) { num_m[u] = alln[v]; } else if(tmp > dps[u]) { dps[u] = tmp; num_s[u] = alln[v]; } else if(tmp == dps[u]&&alln[v] > num_s[u]) { num_s[u] = alln[v]; } } }}void dfs_l(int u, int fa){ l[u] = 0; numl[u] = 1; REP(i, 0, G[u].size()) { int v = G[u][i].to, len = G[u][i].len; if(v!=fa) { dfs_l(v, u); int tmp = l[v]; if(tmp > l[u]) { l[u] = tmp; numl[u] = numl[v]; } else if(tmp == l[u]) { numl[u] += numl[v]; } } }// if(dps[u]==dpm[u])// {// tmp = num_s[u] + num_m[u];// tmp = (tmp*(tmp-1))/2;// tmpl = 2*dpm[u];// }// else// {// if(num_m[u] >= 2)// {// tmpl = dpm[u]*2;// tmp = (num_m[u]*(num_m[u]-1))/2;// }// else// {// tmpl = dps[u]+dpm[u];// tmp = num_m[u]*num_s[u];// }// } int tmpl = 0, tmp = 1; int high = dpm[u], low = dps[u]; int res = 0, cnt = 0, cnt2 = 0; REP(i, 0, G[u].size()) { int v = G[u][i].to, len = G[u][i].len; if(v!=fa) { if(len + alll[v] == high) { res += cnt*alln[v]; cnt += alln[v]; } else if(len + alll[v] == low) { cnt2 += alln[v]; } } } if(low == 0) { cnt2 = 1; } if(res == 0) { res = cnt2*cnt; tmpl = high + low; } else { tmpl = 2*high; } if(tmpl > l[u]) { l[u] = tmpl; numl[u] = res; } else if(tmpl == l[u]) { numl[u] += res; }}void solve(){ dfs(1, 0); dfs_l(1, 0); printf("%d %d\n", l[1], numl[1]);}int main(){ // freopen("7Gin.txt", "r", stdin); //freopen("7Gout.txt", "w", stdout); while(scanf("%d", &n) != EOF) { REP_D(i, 1, n) { G[i].clear(); } REP_D(i, 1, n - 1) { int a, b, w; scanf("%d%d%d", &a, &b, &w); info t; t.to = b; t.len = w; G[a].push_back(t); t.to = a; G[b].push_back(t); } solve(); } return 0;}
0 0
- 最长直径有几个
- 树的最长直径
- 树的直径(最长路)
- uva11324 有向无环图求直径
- 求树中最长路径 树的直径
- hdu 4607 树的最长直径
- loj 1412(树上最长直径的应用)
- uvalive 4728(旋转卡壳求凸包最长直径)
- 求树的直径(最长路径)
- 树的直径模板~~最长路径
- 【codevs】 1814 最长链 树的直径
- 树的直径最长路证明
- 树的直径(最长路)问题
- poj 2187 Beauty Contest 凸包最长直径
- POJ 1985 树的直径(最长链)
- hdu 4607 Park Visit(求树的最长直径)
- 树的直径(最长路) 的详细证明
- 树的直径 (树上的最长路)
- linux几个基本命令
- Linux 常用命令 – 给linux初学者
- linux特有的几个命令
- linux-VI命令整理
- linux用户相关的命令
- 最长直径有几个
- 不要再给自己找借口了,10W年薪,…
- linux教程,linux视频教程,linux…
- 制约个人成长的15种能力
- 优化PHP代码的40条建议
- Linux服务器性能评估与优化
- Loadrunner常见错误
- Project Euler:Problem 8
- 火狐插件火狐黑客插件将Fire…