HDU 4118 树型dp 求树中每个点移位所需总 最小路径和

题意:

T个测试案例

n个点

下面为一棵带权树

问:

1、每个点上站一个人,每个人都走到另一个点上。(一个点上不会有2个人)

2、每个人都想使自己走的很远

3、我们显然可以得到一个解,使得每个人对应一个最终的终点,他们从自己所在点到终点不会绕路走。

 

输出这样的路径和。

思路:

对于每条边,因为大家都想走的最远,那么相当于让边两端的人交换,花费就是 边长*经过边的人数

ans = Σ (每条路长 l )*(经过这条路的最大次数 f )

f = 2 * 这条边左边节点数和右边节点数最小值k. (这样左边的每一个点一定能够对应右边的某个点)

这个k可以dfs 求得.

 

#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}
#define ll long long
#define N 100010
struct Edge{
	int from, to, nex, dis;
}edge[N<<1];
int head[N], edgenum;
void addedge(int u, int v, int dis){
	Edge E = {u, v, head[u], dis};
	edge[ edgenum ] = E;
	head[u] = edgenum++;
}
int num[N], dp[N], n;
ll ans;
void dfs(int u, int fa){
	num[u] = 1; dp[u] = 0;
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to;
		if(v == fa)continue;
		dfs(v, u);
		num[u] += num[v];
		ans += (ll) edge[i].dis* Min( num[v], n-num[v]);
	}

}

int main(){
	int i, T, Cas = 1;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(head, -1, sizeof(head)); edgenum = 0;
		for(i = 1; i < n; i++)
		{
			int u, v, d;scanf("%d %d %d",&u,&v, &d);
			addedge(u, v, d);
			addedge(v, u, d);
		}
		ans = 0;
		dfs(1, -1);
		printf("Case #%d: %I64d\n", Cas++, ans<<1);
	}
	return 0;
}

你可能感兴趣的:(HDU 4118 树型dp 求树中每个点移位所需总 最小路径和)