题目大意:
就是现在又A和B两种颜色, 给一棵树涂色, 每个点u有两种花费A[u]和B[u]代表直接涂上两种颜色分别的花费, 但如果和这点的相连的点被涂色了, 那么吧这个点涂上和相连那个点一样的颜色的话, 花费降至直接涂的一半, 求将这棵树都涂色的最小花费
大致思路:
就是一个树形DP...转移方程什么的看代码注释吧...
代码如下:
Result : Accepted Memory : 1624 KB Time : 0 ms
/*
* Author: Gatevin
* Created Time: 2015/8/2 21:20:04
* File Name: Sakura_Chiyo.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
/*
* 用dp[u][i][j]表示当前在编号为u的点, 这个点选择图为颜色i, 这个点和其子树所在的这一片连通区域是否选择了起点
* 用v表示u的儿子
* 那么不难发现对于dp[u][0][0]其状态只能来自于dp[v][1][1]和dp[v][0][0] (不能来自dp[v][0][1], 因为这样会使得连通处有突破口(起点))
* 对于dp[u][0][1]可以发现起点要么来自这个点u, 这个花费是A[now] + ∑min(dp[v][1][1], dp[v][0][0])
* 要么是以其根节点所在子树为起点, 我是枚举起点是v1那么这个话费是 A[now]/2 + dp[v1][0][1] + ∑min(dp[v2][1][1], dp[v2][0][0])
* 于是去上面两个的最小就好了, 其实后来看了别人的做法发现可以不用枚举v1, 直接取
* A[now] / 2 + ∑min(dp[v][1][1], dp[v][0][0]) + (dp[v1][0][1] - min(dp[v1][1][1], dp[v1][0][0]))最小的
* 也就是去dp[v][0][1] - min(dp[v][1][1], dp[v][0][0])最大的那个v就可以了这样逼我的复杂度低一个级别...
* 不过这个题N = 100也就没什么了...
* 对于dp[u][1][1]和dp[u][1][0]就和dp[u][0][1], dp[u][0][0]对应一个道理了
* 最后结果就是min(dp[1][0][1], dp[1][1][1]) (1作为根)
*/
#define maxn 110
int N;
int A[maxn], B[maxn];
int dp[maxn][2][2];
vector<int> G[maxn];
void dfs(int now, int fa)
{
int nex, nex2;
for(int i = 0, sz = G[now].size(); i < sz; i++) if((nex = G[now][i]) != fa)
dfs(nex, now);
if(G[now].size() == 1 && fa != -1)
{
dp[now][0][0] = A[now] / 2;
dp[now][0][1] = A[now];
dp[now][1][0] = B[now] / 2;
dp[now][1][1] = B[now];
return;
}
dp[now][0][0] = A[now] / 2;
int selectNow = A[now];
int selectSon = 1e9;
for(int i = 0, sz = G[now].size(); i < sz; i++) if((nex = G[now][i]) != fa)
{
dp[now][0][0] += min(dp[nex][0][0], dp[nex][1][1]);
selectNow += min(dp[nex][0][0], dp[nex][1][1]);
int tmp = A[now] / 2 + dp[nex][0][1];
for(int j = 0; j < sz; j++) if(i != j && (nex2 = G[now][j]) != fa)
tmp += min(dp[nex2][1][1], dp[nex2][0][0]);
selectSon = min(selectSon, tmp);
}
dp[now][0][1] = min(selectNow, selectSon);
dp[now][1][0] = B[now]/2;
selectNow = B[now];
selectSon = 1e9;
for(int i = 0, sz = G[now].size(); i < sz; i++) if((nex = G[now][i]) != fa)
{
dp[now][1][0] += min(dp[nex][1][0], dp[nex][0][1]);
selectNow += min(dp[nex][0][1], dp[nex][1][0]);
int tmp = B[now] / 2 + dp[nex][1][1];
for(int j = 0; j < sz; j++) if(i != j && (nex2 = G[now][j]) != fa)
tmp += min(dp[nex2][0][1], dp[nex2][1][0]);
selectSon = min(selectSon, tmp);
}
dp[now][1][1] = min(selectNow, selectSon);
return;
}
int main()
{
while(~scanf("%d", &N))
{
for(int i = 1; i <= N; i++) scanf("%d", A + i);
for(int i = 1; i <= N; i++) scanf("%d", B + i);
for(int i = 1; i <= N; i++) G[i].clear();
int u, v;
for(int i = 1; i < N; i++)
{
scanf("%d %d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, -1);
printf("%d\n", min(dp[1][1][1], dp[1][0][1]));
}
return 0;
}