很明显的树状DP。
状态:dp[i][j][k]
i:第i个城市
j:为0时用A占领;为1时用B占领
k:为0时,全部取了一半的时间;为1时,已经有一个连通的城市选取了完整的价值。
假设城市1为树的根,最终的答案就为:min(dp[1][0][1], dp[1][1][1])
转移:
假设正搜索到第u个城市,它的叶子节点已经搜索完成。
dp[i][0][0]:
初值:A[u] / 2;
如果儿子被A占领,dp[u][0][0] += dp[v][0][0];
如果儿子被B占领,dp[u][0][0] += dp[v][1][1];
结果:dp[u][0][0] = sum{min(dp[v][0][0], dp[v][1][1])} + A[u] / 2;
同理:dp[u][1][0] = sum{min(dp[v][1][0], dp[v][0][1]]} + B[u] / 2;
dp[i][0][1]:
如果当前节点付出全额代价:
初值:A[u]
如果儿子被A占领,dp[u][0][1] += dp[v][0][0];
如果儿子被B占领,dp[u][0][1] += dp[v][1][1];
如果让子孙节点付出全额代价:
初值:A[u] / 2
如果儿子被A占领,dp[u][0][1] += dp[v][0][0];
如果儿子被B占领,dp[u][0][1] += dp[v][1][1];
选择一个儿子付出代价,这个代价必须最小:min(dp[v][0][1] - min(dp[v][0][0], dp[v][1][0]));
DB = min(dp[v][1][1] - min(dp[v][1][0], dp[v][0][1]));
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<memory.h>
#include<queue>
#include<stack>
using namespace std;
#define N 105
#define INF 1<<30
int dp[N][2][2];//dp[i][j][k] k=0代表i点边上有用j攻占过的城市 此时dp[u][j][]=j[i]/2
int a[N],b[N],g[N][N]; // g[i][j] 代表i点连接的第j个点的编号
inline int min(int a,int b){return a>b?b:a;}
inline void addedge(const int &u, const int &v)
{
g[u][++g[u][0]] = v;
}
void dfs(int u,int father)
{
if(g[u][0]==1 && father!= -1)//是叶子节点[ father!=-1:排除根节点 (有可能根节点的出度也是1)]
{
dp[u][0][0] = a[u]/2;
dp[u][1][0] = b[u]/2;
dp[u][0][1] = a[u];
dp[u][1][1] = b[u];
}
else
{
int sa=0,sb=0;//u点下面的子树的值
int da=INF,db=INF;
for(int i=1;i<=g[u][0];i++)
{
int v=g[u][i];//u点向下连接的所有的点
if(v!=father)//不是过来的那个点(即 不是u 的父节点)
{
dfs(v,u);//一直搜到叶子节点
sa += min(dp[v][0][0], dp[v][1][1]); //v这点用A打
sb += min(dp[v][1][0], dp[v][0][1]); //v这点用B打
da = min(da, dp[v][0][1] - min(dp[v][0][0], dp[v][1][1]));
db = min(db, dp[v][1][1] - min(dp[v][1][0], dp[v][0][1]));
}
}
dp[u][0][0] = sa + (a[u] >> 1);//打u的军队和打v的军队都是A
dp[u][1][0] = sb + (b[u] >> 1);
dp[u][0][1] = min(sa + a[u], sa + (a[u] >> 1) + da); //u这点用a打和不用a打
dp[u][1][1] = min(sb + b[u], sb + (b[u] >> 1) + db);
}
}
int main()
{
int n,i;
while(cin>>n){
for(i=1;i<=n;i++)cin>>a[i];
for(i=1;i<=n;i++)cin>>b[i];
memset(g,0,sizeof(g));
for(i=1;i<n;i++)
{
int u,v; cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
memset(dp,0,sizeof(dp));
dfs(1,-1);
cout<<min(dp[1][0][1],dp[1][1][1])<<endl;
}
return 0;
}