[USACO10MAR]伟大的奶牛聚集 (树形dp)

本文深入探讨了树形DP算法的实现细节,通过一个具体的例子,详细解释了如何利用DP来求解树上节点间距离的最小化问题。文章首先定义了关键变量,如点权和、总代价等,然后逐步推导出DP状态转移方程,最后通过代码展示了算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uuuvvv的父亲,dp[u]dp[u]dp[u]是走到uuu的总代价。
tottottot是总点权,c[u]c[u]c[u]uuu和它的子树的点权和。
可以发现,集合点从uuu变成vvv的总代价变动为:
1:u1:u1:u和它的子树向vvv(u,v)−>c[u]∗(u,v)(u,v)->c[u]*(u,v)(u,v)>c[u](u,v)
2:2:2: 其他的所有节点向uuu(u,v)−>−(tot−c[u])∗(u,v)(u,v)->-(tot-c[u])*(u,v)(u,v)>(totc[u])(u,v)
dp[v]=dp[u]+c[u]∗(u,v)−(tot−c[u])∗(u,v)dp[v]=dp[u]+c[u]*(u,v)-(tot-c[u])*(u,v)dp[v]=dp[u]+c[u](u,v)(totc[u])(u,v)

LonglongLonglongLonglong almostalmostalmost killedkilledkilled me.me.me.

#include<cstdio>

const int MAXN = 1e5 + 10;
int N, cnt = 0;
long long tot = 0;
long long dp[MAXN] = {0};
int c[MAXN], siz[MAXN], h[MAXN];
long long ans = 1000000000000000000;
struct E{
	int t, val, nxt;
}Ed[2 * MAXN];

void Dfs(int k, int fa)
{
	siz[k] = c[k];
	for (int i = h[k]; i; i = Ed[i].nxt)
	{
		int u = Ed[i].t; if (u == fa) continue;
		Dfs(u, k); siz[k] += siz[u];
		dp[1] += 1LL * siz[u] * Ed[i].val;
 	}
}

void Dp(int k, int fa)
{
	for (int i = h[k]; i; i = Ed[i].nxt)
	{
		int u = Ed[i].t; if (u == fa) continue;
		dp[u] = dp[k] - 1LL * siz[u] * Ed[i].val + 1LL * (tot - siz[u]) * Ed[i].val;
		Dp(u, k);
	}
}

void Add(int f, int t, int v) {Ed[++cnt].t = t, Ed[cnt].val = v, Ed[cnt].nxt = h[f], h[f] = cnt;}

long long min(long long a, long long b){return a < b ? a : b;}

int main()
{
	scanf("%d", &N);
	for (int i = 1; i <= N; i++) scanf("%d", &c[i]), tot += c[i];
	for (int i = 1; i < N; i++)
	{
		int f, t, v; scanf("%d%d%d", &f, &t, &v);
		Add(f, t, v), Add(t, f, v);
	}
	Dfs(1, 0); Dp(1, 0);
	for (int i = 1; i <= N; i++) ans = min(ans, dp[i]);
	printf("%lld", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值