【USACO】Luogu P2986 Great Cow Gathering G (dfs,树形dp)

来源:Luogu P2986,JZOJ

题目描述

B e s s i e Bessie Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。

每个奶牛居住在 N ( 1 < = N < = 100 , 000 ) N(1<=N<=100,000) N(1<=N<=100,000) 个农场中的一个,这些农场由 N − 1 N-1 N1 条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场 A i A_i Ai B i ( 1 < = A i < = N ; 1 < = B i < = N ) B_i(1 <= A_i <=N; 1 <= B_i <= N) Bi(1<=Ai<=N;1<=Bi<=N),长度为 L i ( 1 < = L i < = 1 , 000 ) L_i(1 <= L_i <= 1,000) Li(1<=Li<=1,000)。集会可以在 N N N 个农场中的任意一个举行。另外,每个牛棚中居住者 C i ( 0 < = C i < = 1 , 000 ) C_i(0 <= C_i <= 1,000) Ci(0<=Ci<=1,000) 只奶牛。

在选择集会的地点的时候, B e s s i e Bessie Bessie 希望最大化方便的程度(也就是最小化不方便程度)。比如选择第 X X X 个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和,(比如,农场i到达农场 X X X 的距离是 20 20 20,那么总路程就是 C i ∗ 20 C_i*20 Ci20)。帮助 B e s s i e Bessie Bessie 找出最方便的地点来举行大集会。

Consider a country with five barns with [various capacities] connected by various roads of varying lengths. In this set of barns, neither barn 3 nor barn 4 houses any cows.

1 3 4 5

@–1--@–3--@–3--@[2]

[1] |

2 | @[1] 2 Bessie can hold the Gathering in any of five barns; here is the table of inconveniences calculated for each possible location:

Gather ----- Inconvenience ------

Location B1 B2 B3 B4 B5 Total

1 0 3 0 0 14 17

2 3 0 0 0 16 19

3 1 2 0 0 12 15

4 4 5 0 0 6 15

5 7 8 0 0 0 15

If Bessie holds the gathering in barn 1, then the inconveniences from each barn are:

Barn 1 0 – no travel time there!

Barn 2 3 – total travel distance is 2+1=3 x 1 cow = 3 Barn 3 0 – no cows there!

Barn 4 0 – no cows there!

Barn 5 14 – total travel distance is 3+3+1=7 x 2 cows = 14 So the total inconvenience is 17.

The best possible convenience is 15, achievable at by holding the Gathering at barns 3, 4, or 5.

解题思路

  • 这道题是一道树形 d p dp dp,先 d f s dfs dfs 一遍,用 s i z [ x ] siz[x] siz[x] 存储以 x x x 为根的子树的节点数量, f [ i ] f[i] f[i] 表示以 i i i 为根的子树到根的距离之和,那么 f [ 1 ] f[1] f[1] 就是所有奶牛到 1 1 1 点的距离之和了;
  • 然后就要利用到换根思想, d i s [ y ] = 1 L L ∗ d i s [ x ] − s i z [ y ] ∗ e [ i ] . v + ( s u m − s i z [ y ] ) ∗ e [ i ] . v ; dis[y]=1LL*dis[x]-siz[y]*e[i].v+(sum-siz[y])*e[i].v; dis[y]=1LLdis[x]siz[y]e[i].v+(sumsiz[y])e[i].v;
  • 想想为什么,因为当根节点换成了 y y y 时, y y y 子树下的点就少走了当前这条连接 x x x y y y 的边,然而除去 y y y 子树的另外点,又要多走这一条边。(也许有些抽象)

Code

#include <bits/stdc++.h>
using namespace std;
int n,t=0;
long long sum=0,ans=1e15,dis[200010],siz[200010],f[200010],c[200010],linkk[200010];
struct node
{
	long long y,v,next;
}e[200010];
void insert(int x,int y,int v)  //邻接表插入
{
	e[++t].y=y; e[t].v=v;
	e[t].next=linkk[x]; linkk[x]=t;
}
void dfs(int x,int father)  //深度优先搜索dfs
{
	siz[x]=c[x];  //siz[x]表示以x为根的子树的节点数量
	for (int i=linkk[x];i;i=e[i].next)  //邻接表遍历
	{
		int y=e[i].y;
		if (y!=father)
		{
			dfs(y,x);
			siz[x]+=siz[y];  //把y为根的节点数加到以x为根的节点数中
			f[x]=f[x]+f[y]+siz[y]*e[i].v;  //f[i]表示以i为根的子树到根的距离之和 
		}
	}
}
void treedp(int x,int father)
{
	for (int i=linkk[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if (y!=father)
		{
			dis[y]=1LL*dis[x]-siz[y]*e[i].v+(sum-siz[y])*e[i].v;  //换根思想
			ans=min(ans,dis[y]);
			treedp(y,x);
		}
	}
}
int main()
{
	freopen("gather.in","r",stdin);
	freopen("gather.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%lld",&c[i]);
		sum+=c[i];
	}
	for (int i=1;i<n;i++)
	{
		int x,y,v;
		scanf("%d %d %d",&x,&y,&v);
		insert(x,y,v);
		insert(y,x,v);
	}
	dfs(1,0);
	dis[1]=f[1];  //聚集到点1的花费
	ans=min(ans,dis[1]);
	treedp(1,0);
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值