BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)
Posted forever97‘s blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)相关的知识,希望对你有一定的参考价值。
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1827
【题目大意】
给出一棵有点权和边权的树,
请确定一个点,使得每个点到这个点的距离乘上该点乘积的总和最小。
【题解】
定1为根,我们先计算当这个点为1的时候的值,同时记录每个子树的size
之后我们再做一遍dfs,计算出每个点作为中心时候的答案
我们发现当一个点从父节点往子节点移动的时候
对于答案的变化是ans+=(size[1]-2*size[x])*len(fx->x)
所以我们dfs计算,保留最小值即可。
【代码】
#include <cstdio> #include <algorithm> #include <vector> #include <utility> using namespace std; const int N=100010; typedef pair<int,int> P; typedef long long LL; vector<P> v[N]; int d[N],size[N],n; LL ans,ans1; void dfs(int x,int fx){ for(int i=0;i<v[x].size();i++){ int y=v[x][i].first,z=v[x][i].second; if(y!=fx){ d[y]=d[x]+z; ans+=(LL)size[y]*d[y]; dfs(y,x); size[x]+=size[y]; } } } void dfs2(int x,int fx){ for(int i=0;i<v[x].size();i++){ int y=v[x][i].first,z=v[x][i].second; if(y!=fx){ ans1+=(LL)(size[1]-2*size[y])*z; if(ans1<ans)ans=ans1; dfs2(y,x); ans1-=(LL)(size[1]-2*size[y])*z; } } } int main(){ while(~scanf("%d",&n)){ ans=ans1=0; for(int i=1;i<=n;i++)scanf("%d",&size[i]); for(int i=1;i<n;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); v[a].push_back(P(b,c)); v[b].push_back(P(a,c)); }dfs(1,-1);ans1=ans; dfs2(1,-1); printf("%lld\n",ans); }return 0; }
以上是关于BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)的主要内容,如果未能解决你的问题,请参考以下文章
嘴巴题4 「BZOJ1827」[Usaco2010 Mar] gather 奶牛大集会
BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)
BZOJ1827 [Usaco2010 Mar]gather 奶牛大集会
BZOJ 1827 洛谷 2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gather