Apple Transportation
ZOJ - 3231
There's a big apple tree in the forest. In the tree there are N nodes (numbered from 0 to N - 1), and the nodes are connected by branches. On each node of the tree, there is a squirrel. In the autumn, some apples will grow on the nodes. After all apples are ripe, each squirrel will collect all the apples of their own node and store them. For the demand to be harmonic, they decide to redistribute the apples to minimize the variance (please refer to the hint) of apples in all nodes. Obviously, an apple cannot be divided into several parts. To reach this goal, some transportation should be taken. The cost of transporting x apples from node u to node v is x * distance (node u, node v). Now given the current amount of apples of each node and the structure of the apple tree, you should help the squirrels to find the minimal cost to redistribute the apples.
Input
Input consists of multiple test cases (less than 80 cases)!
For each test case, the first line contains an integer N (1 <= N <= 100), which is the number of the nodes in the tree.
The following line contains N integers a0,a1,...,aN-1 (0 <= ai <= 10000), representing the amount of the i-th node's apples.
The following N - 1 lines each contain three integers u, v, c (0 <= u,v <= N - 1, 0 <= c <= 1000), which means node u and node v are connected by a branch, the length of the branch is c.
There is a blank line between consecutive cases.
Output
For each case output the minimal total transportation cost. The minimal cost is guaranteed to be less than 231.
Sample Input
3 1 2 3 0 1 1 0 2 1 3 1 3 3 0 1 3 0 2 4 2 1 2 0 1 1
Sample Output
1 3 0
Hint
The formula to calculate the variance of x1, x2, ..., xn:
My Solution
题意:有一颗n节点的苹果树,每个节点上有一定数量的苹果ai,树上有一些松鼠,他们想让苹果平均分配,即每个节点的方差最小。它们可以任意地将苹果在节点之间移动,
每移动一个苹果所花费的代价是移动的路程。求最小的总代价。
树形dp
方差最小其实就是等价于 有 sigma{ai} mod n个节点上有 sigma{ai} / n + 1个苹果,其他都有 sigma{ai} / n 个。
f[i][j]表示在节点i代表的子树中有j个节点上有 sigma{ai} / n + 1个苹果,其他的为sigma{ai} / n 时的最小代价。
f[u][j] = min{sigma{f[v][numt] + abs(sum[v] - cnt[v] * average - numt)*diat[u][v]]}}
其中numt表示这个子节点v代表的子树有 numt个节点上有 sigma{ai} / n + 1个苹果,有cnt[v]个节点,sum[v]个苹果,
需要枚举numt,且要求保证 sigma{numt} == j..
最终答案是 f[0][res].
复杂度 小于 O(n^3)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e2 + 8;
int head[MAXN], tot;
struct esge{
int u, v, w, nxt;
} a[2*MAXN];
inline void add(int u, int v, int w)
{
tot++;
a[tot].u = u, a[tot].v = v, a[tot].w = w;
a[tot].nxt = head[u], head[u] = tot;
}
LL f[MAXN][MAXN], tmp[MAXN];
int val[MAXN], cnt[MAXN], sum[MAXN], ave, res;
inline void dfs(int u, int fa)
{
f[u][0] = f[u][1] = 0;
cnt[u] = 1; sum[u] = val[u];
int i, j, k, v;
for(k = head[u]; k; k = a[k].nxt){
if(a[k].v == fa) continue;
v = a[k].v;
dfs(v, u);
memset(tmp, 127, sizeof tmp);
for(i = cnt[u] - 1; i >= 0; i--){
for(j = cnt[v]; j >= 0; j--){
if(cnt[u] == 1){
tmp[i+j] = f[v][j] + abs(sum[v] - cnt[v]*ave - j)*a[k].w;
}
else{
tmp[i+j] = min(tmp[i+j], f[u][i] + f[v][j] + abs(sum[v] - cnt[v]*ave - j)*a[k].w);
}
}
}
cnt[u] += cnt[v];
sum[u] += sum[v];
for(i = 0; i <= cnt[u]; i++){
f[u][i] = tmp[i];
}
}
for(i = cnt[u]; i >= 1; i--) f[u][i] = min(f[u][i], f[u][i-1]); //考虑子树的根节点有 average + 1 个苹果的情况
}
int main()
{
#ifdef LOCAL
freopen("1.in", "r", stdin);
//freopen("1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false); cin.tie(0);
int n, u, v, w, i, s;
while(cin >> n){
memset(f, 127, sizeof f);
memset(a, 0, sizeof a);
memset(head, 0, sizeof head);
s = 0; tot = 1;
for(i = 0; i < n; i++){
cin >> val[i];
s += val[i];
}
for(i = 1; i < n; i++){
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
ave = s / n;
res = s % n;
dfs(0, -1);
cout << f[0][res] << "\n";
}
return 0;
}
Thank you!
------from ProLights