Description
Data Constraint
Data Constraint
对于20%的数据,N<=15
对于100%的数据,T<=10,N<=100,0<=si<=10000,1<=X,Y<=N,1<=Z<=10000。
Solution
经过观察可以发现,每一种平衡状态一定是由sum个x和sum1个x+1组成的。
其中
s
u
m
1
=
∑
a
i
n
sum1=\frac{\sum a_{i}}{n}
sum1=n∑ai
s
u
m
=
n
−
s
u
m
1
sum=n-sum1
sum=n−sum1
可以考虑树型dp。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示以
i
i
i号节点为根的子树油桶数为
x
+
1
x+1
x+1的节点数为
j
j
j的最小代价
那么状态转移方程为:
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
]
[
j
−
k
]
+
f
[
s
o
n
]
[
k
]
+
a
b
s
(
s
[
i
]
−
x
∗
(
s
i
z
e
[
s
o
n
]
−
j
)
−
(
x
+
1
)
∗
j
)
∗
l
e
n
)
f[i][j]=min(f[i][j-k]+f[son][k]+abs(s[i]-x*(size[son]-j)-(x+1)*j)*len)
f[i][j]=min(f[i][j−k]+f[son][k]+abs(s[i]−x∗(size[son]−j)−(x+1)∗j)∗len)
其中
s
[
i
]
s[i]
s[i]为以i为根的子树中总的初始油桶数量,
s
i
z
e
[
s
o
n
]
size[son]
size[son]表示以
s
o
n
son
son为根的子树的节点数。这句话的意思就是把儿子多出来的运到父亲这,如果儿子少了,就是从父亲这运过来,所以要取绝对值。
这道题还可以用费用流做,只不过我太弱,不会做。
Code
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
int T,n,cnt,sum,val,val1,Size;
int a[101],head[101],size[101];
ll s[101],f[101][101],g[101];
struct node {
int to,len,next;
}edge[201];
inline int read() {
int s=0;
char ch=getchar();
while(ch<48||ch>57)ch=getchar();
while(ch>=48&&ch<=57)
s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s;
}
inline void add(int x,int y,int z) {
edge[cnt]=(node){y,z,head[x]};
head[x]=cnt++;
}
inline void dfs(int now,int fa) {
size[now]=1;s[now]=a[now];
f[now][0]=f[now][1]=0;
for(int i=head[now];i!=-1;i=edge[i].next) {
int son=edge[i].to;
if(son==fa)continue;
dfs(son,now);
}
for(int i=head[now];i!=-1;i=edge[i].next) {
int son=edge[i].to,len=edge[i].len;
if(son==fa)continue;
size[now]+=size[son];
s[now]+=s[son];
memset(g,0x7f7f7f7f,sizeof(g));
for(int j=0;j<=Size&&j<=size[now];++j)
for(int k=0;k<=size[son]&&k<=j;++k)
g[j]=min(g[j],f[now][j-k]+f[son][k]+abs(s[son]-(size[son]-k)*val-k*(val+1))*len);
//不能直接转移,要把所有答案存下来再转移过去。不然会重复
for(int j=0;j<=Size&&j<=size[now];j++)f[now][j]=g[j];
}
}
int main() {
T=read();
while(T--) {
n=read();cnt=0;sum=0;
for(int i=1;i<=n;++i)
a[i]=read(),sum+=a[i],head[i]=-1;
Size=sum%n;val=sum/n;
for(int i=1;i<n;++i) {
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
}
memset(f,0x7f7f7f7f,sizeof(f));
dfs(1,0);
printf("%lld\n",f[1][Size]);
}
}