HDU 3534 Tree (树形dp求树的直径)

Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1894    Accepted Submission(s): 620


 

Problem Description

In the Data structure class of HEU, the teacher asks one problem: How to find the longest path of one tree and the number of such longest path?

 

 

Input

There are several test cases. The first line of each case contains only one integer N, means there are N nodes in the tree. N-1 lines follow, each line has three integers w,v and len, indicate that there is one edge between node w and v., and the length of the edge is len.
 

 

 

Output

For each test case, output the length of longest path and its number in one line.

 

 

Sample Input

 

4 1 2 100 2 3 50 2 4 50 4 1 2 100 2 3 50 3 4 50

 

 

Sample Output

 

150 2 200 1

 题目大意 : 输入一个树, 输出该数的最大边长和拥有最大边长的数目

思路 : 如果单纯求树的直径的话, 可以用两次dfs解决, 但是这样只能求出直径,无法求出数目了, 要想连同数目一起求出来, 还得枚举所有的叶子, 这样肯定超时, 所以用树形dp, 在记录直径的同时记录数量。 记录直径的原理就是, 任取一点当根, 一直搜到底, 然后开始往上更新长度, 当碰到一个点有不止一条链的时候,开始更新他的长度即数量, 当出现新的最大长度, 数量就是两个点的数量之积, 如果长度和最大长度相同, 则加上他们二者数量的乘积

Accepted coded

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 15;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct Edge
{
	int v, w, next;
}e[MAXN << 1];
int head[MAXN], n, k, cnt, ans;
int dis[MAXN], num[MAXN];
void init() {
	MEM(head, -1); cnt = k = 0;
	ans = -INF;
}
void add(int from, int to, int wi) {
	e[++cnt].v = to;
	e[cnt].w = wi;
	e[cnt].next = head[from];
	head[from] = cnt;
}
void dfs(int x, int fa) {
	dis[x] = 0, num[x] = 1;
	for (int i = head[x]; i != -1; i = e[i].next) {
		int vi = e[i].v;
		if (vi != fa) {
			dfs(vi, x);
			if (dis[x] + dis[vi] + e[i].w > ans) { // 最大长度的更新
				ans = dis[x] + dis[vi] + e[i].w;
				k = num[x] * num[vi];  
			}
			else if (dis[x] + dis[vi] + e[i].w == ans) // 相等时的更新
				k += num[x] * num[vi];
			if (dis[x] < dis[vi] + e[i].w) {  // 更新点和数量
				dis[x] = dis[vi] + e[i].w;
				num[x] = num[vi];
			}
			else if (dis[x] == dis[vi] + e[i].w) // 更新数量
				num[x] += num[vi];
		}
	}
}

int main()
{
	while (~sc("%d", &n)) {
		init();
		for (int i = 1; i < n; i++) {
			int ui, vi, wi;
			sc("%d %d %d", &ui, &vi, &wi);
			add(ui, vi, wi); add(vi, ui, wi);
		}
		dfs(1, 1);
		cout << ans << " " << k << endl;
	}
 	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值