【BZOJ】1827: [Usaco2010 Mar]gather 奶牛大集会(树形dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=1827
仔细想想就好了,,
每个点维护两个值,一个是子树的费用,一个是除了子树和自己的费用。都可以用dfs做。
维护第一个就是简单的dp。d1[i]=sum{d1[j]+w(i, j)*son1[j]},j是i的子女
第二个就有些麻烦,因为要考虑的不只是这个点的父亲,还要考虑这个点父亲的子树。
那么
d2[i]=d2[fa]+w(fa, i)*son1[i]+d1[fa]-d1[i]
而在处理这些方程有一些细节,不一定完全和上边的的方程一样,具体看代码
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> using namespace std; typedef long long ll; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%lld", a) #define dbg(x) cout << (#x) << " = " << (x) << endl #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; } #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const ll min(const ll &a, const ll &b) { return a<b?a:b; } const int N=100005; int ihead[N], cnt, n; struct ED { int to, next; ll w; }e[N<<1]; ll d[N][2], ans=~0ull>>1, c[N], son[N][2]; void add(int u, int v, ll w) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].w=w; e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].w=w; } void dfs1(int x, int fa) { int y; for(int i=ihead[x]; i; i=e[i].next) if((y=e[i].to)!=fa) { ll w=e[i].w; dfs1(y, x); son[x][0]+=son[y][0]+c[y]; d[x][0]+=d[y][0]+w*(son[y][0]+c[y]); } } void dfs2(int x, int fa) { int y; for(int i=ihead[x]; i; i=e[i].next) if((y=e[i].to)!=fa) { ll w=e[i].w; son[y][1]=son[x][1]+c[x]+son[x][0]-son[y][0]-c[y]; d[y][1]=d[x][1]+w*son[y][1]+d[x][0]-d[y][0]-w*(son[y][0]+c[y]); dfs2(y, x); } } int main() { read(n); for1(i, 1, n) read(c[i]); rep(i, n-1) { int u=getint(), v=getint(), w=getint(); add(u, v, w); } dfs1(1, 0); dfs2(1, 0); for1(i, 1, n) ans=min(ans, d[i][0]+d[i][1]); print(ans); return 0; }
Description
Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将 来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),长度为L_i(1 <= L_i <= 1,000)。集会可以在N个农场中的任意一个举行。另外,每个牛棚中居住者C_i(0 <= C_i <= 1,000)只奶牛。在选择集会的地点的时候,Bessie希望最大化方便的程度(也就是最小化不方便程度)。比如选择第X个农场作为集会地点,它的不方 便程度是其它牛棚中每只奶牛去参加集会所走的路程之和,(比如,农场i到达农场X的距离是20,那么总路程就是C_i*20)。帮助Bessie找出最方 便的地点来举行大集会。 考虑一个由五个农场组成的国家,分别由长度各异的道路连接起来。在所有农场中,3号和4号没有奶牛居住。
Input
第一行:一个整数N * 第二到N+1行:第i+1行有一个整数C_i * 第N+2行到2*N行,第i+N+1行为3个整数:A_i,B_i和L_i。
Output
* 第一行:一个值,表示最小的不方便值。
Sample Input
5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
Sample Output
15
HINT
Source
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。