首页 > 代码库 > BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)
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)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。