[USACO10MAR]Great Cow Gathering G 题解报告
题目描述
Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。
每个奶牛居住在 N 个农场中的一个,这些农场由 N−1 条道路连接,并且从任意一个农场都能够到达另外一个农场。道路 ii 连接农场\(Ai\) 和 \(Bi\),长度为 \(Li\)。集会可以在 \(N\) 个农场中的任意一个举行。另外,每个牛棚中居住着 Ci 只奶牛。
在选择集会的地点的时候,Bessie 希望最大化方便的程度(也就是最小化不方便程度)。比如选择第 X 个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和(比如,农场 i 到达农场 X 的距离是 20,那么总路程就是 Ci×20)。帮助 Bessie 找出最方便的地点来举行大集会。
输入输出格式
输入格式
第一行一个整数 N 。 第二到 N+1 行:第 i+1 行有一个整数 Ci。 第 N+2 行到 2*N 行:第 i+N+1 行为 3 个整数:\(Ai\),\(Bi\) 和 \(Li\)。
输出格式
一行一个整数,表示最小的不方便值。
输入输出样例
输入样例 #1
5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
输出样例 #1
15
说明
1≤N≤105,1≤Ai≤Bi≤N,0≤Ci,Li≤1000。
思路
读题下来
相当于就是求在一棵无根树中找一个根节点,使得所有点的深度之和最小
即换根DP
注意,跟[POI2008] STA-Station不同的是,在算深度的时候,要乘上当前节点的奶牛数。
递推公式:跟[POI2008] STA-Station一样,不过这里dx的定义有一点点不同
我们可以在第一个dfs中算出在以u为根节点的子树的深度之和,即子树中所有子节点到u的深度之和
还是用两个dfs
第一次,以1为根节点计算一次
第二次计算偏移后的值
最后计算最小值
求出答案
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200100;
ll d[N],c[N],tot[N],f[N],h[N];
ll sum,ans=0x3f,cnt=0,n;
struct Node {
ll v,nxt,w;
} tr[N];
void dfsa(ll u,ll fa) {
ll cnt=0;
for(ll i=h[u]; i; i=tr[i].nxt) {
ll v=tr[i].v;
if(v!=fa) {
ll s=dfsa(v,u);
d[u]+=d[v]+tr[i].w*s;
cnt+=s;
}
}
tot[u]=cnt+c[u];
}
void dfsb(ll u,ll fa) {
for(ll i=h[u]; i; i=tr[i].nxt) {
ll v=tr[i].v;
if(v!=fa) {
ll w=tr[i].w;
f[v]=f[u]-tot[v]*w+(sum-tot[v])*w;
dfsb(v,u);
}
}
}
void add(int u,int v){
tr[++cnt].to=v;
tr[cnt].nxt=hd[u];
hd[u]=cnt;
}
int main() {
scanf("%d",&n);
for(ll i=1; i<=n; ++i) {
scanf("%d",&c[i]);
sum+=c[i];
}
for(ll i=1; i<n; ++i) {
scafn("%lld%lld%lld",&u,&v,&w);
ans(u,v,w);
ans(v,u,w);
}
dfsa(1,1);
dfsb(1,1);
for(ll i=1; i<=n; ++i){
ans=min(ans,f[i]);
}
printf("%ll,ans+d[1]);
return 0;
}
完结撒花❀
**

浙公网安备 33010602011771号