这个状态的定义非常难想吧...
$f[x][y]$ 表示以 $x$ 为根的子树中,其余点全部移到了应该移动到的位置,也建设了应该建设的仓库,而 $x$ 移动到 $y$ 的最小代价.
这里是事前钦定 $y$ 不建立仓库的.
那么,我们考虑如何从 $x$ 的儿子转移到 $x$:
若 $f[son][b]$ 中 $b$ 与 $y$ 相等,则 $f[x][y]=f[x'][y]+f[son][y]$
若 $f[son][b]$ 中 $b$ 与 $y$ 不相等,且 $b$ 在 $son$ 的子树中,则直接让 $son$ 去 $b$ 就好了.
最后一种情况:$b$ 与 $y$ 不相等,且 $b$ 在 $son$ 的子树外,那么你发现这个一定没有 $b$ 与 $y$ 相等的优,按照第二种方式转移就行(反正不会起贡献)
code:
#include <cstdio>
#include <string>
#include <cstring>
#define N 205
#define ll long long
using namespace std;
void setIO(string s)
{
freopen((s+".in").c_str(),"r",stdin);
}
int n,K,edges;
int val[N],dis[N][N],hd[N],to[N<<1],nex[N<<1],f[N][N];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs(int u,int ff)
{
for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff) dfs(to[i],u);
for(int i=1;i<=n;++i)
{
f[u][i]=dis[u][i];
for(int j=hd[u];j;j=nex[j])
{
int y=to[j];
int tmp=f[y][i];
if(y==ff) continue;
for(int k=1;k<=n;++k) tmp=min(tmp,f[y][k]+K);
f[u][i]+=tmp;
}
}
}
void getdis(int pr,int d,int u,int ff)
{
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff) dis[pr][to[i]]=val[d],getdis(pr,d+1,to[i],u);
}
int main()
{
// setIO("input");
int i,j;
scanf("%d%d",&n,&K);
for(i=1;i<n;++i) scanf("%d",&val[i]);
for(i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(i=1;i<=n;++i) getdis(i,1,i,0);
dfs(1,0);
int cur=1e9;
for(i=1;i<=n;++i) cur=min(cur,f[1][i]);
printf("%d\n",cur+K);
return 0;
}