一道动态规划的题目,首先要利用DFS将无根树变为有根树。然后从根开始,这个时候就可以分为两种情况来进行考虑:第一种情况是与根相连接的子节点中至少有一个子节点使用的是B装置,第二种情况是与根节点相连接的所有子节点使用的都不是B装置,对于第一种情况,首先递归算出所有的子节点的最小代价之和,然后对于每一个子节点,都尝试去除当前最优的放置方案,强制放置一个B装置得到的新的代价之和,求出所有的新的代价之和的最小值并且进行保存。对于第二种情况,首先判断当前的节点与其子节点所连接的边是否是激活状态(激活状态只能存在两种情况:第一种情况是当前的节点上放置的是A装置,或者是当前节点相连接的父节点放置的是B装置),然后考虑剩下的两种情况的最小值:对应的子节点放置的是A装置以及对应的子节点没有放置装置,然后求出所有情况的最小值并且返回即可,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
using namespace std;
const int MAX = 10010;
class Edge{
public:
int from;
int to;
int next_e;
};
int dp[MAX][3][3][2];//村庄的个数
Edge edge[MAX*2];
int head[MAX];
int fa[MAX];
class Solve{
public:
int n, c1, c2;
int amount;
void addEdge(int from,int to){
edge[amount].from = from;
edge[amount].to = to;
edge[amount].next_e = head[from];
head[from] = amount++;
}
void dfs(int a,int b){
fa[a] = b;
for (int i = head[a]; i != -1; i = edge[i].next_e){
if (edge[i].to != b){
dfs(edge[i].to, a);
}
}
}
void Init(){
amount = 0;
memset(head,-1,sizeof(head));
for (int i = 1; i < n; i++){
int a, b;
cin >> a >> b;
addEdge(a, b);
addEdge(b, a);
}
dfs(1, 0);
memset(dp,-1,sizeof(dp));
}
int DP(int ind,int a,int b,int c){
if (dp[ind][a][b][c] !=-1) return dp[ind][a][b][c];
int ans = 1<<30;
int cur = 0;
for (int i = head[ind]; i != -1;i=edge[i].next_e){//至少有一个装置为B
int ind2 = edge[i].to;
if (ind2 != fa[ind]){
cur += min(min(DP(ind2, 0, a, 1), DP(ind2, 1, a, 1)), DP(ind2, 2, a, 1));
}
}
for (int i = head[ind]; i != -1; i = edge[i].next_e){
int ind2 = edge[i].to;
if (ind2 != fa[ind]){
int temp = min(min(DP(ind2, 0, a, 1), DP(ind2, 1, a, 1)), DP(ind2, 2, a, 1));
ans = min(ans, cur - temp + DP(ind2, 2, a, 1));
}
}
if (c != 0){//不存在装置B
int state = (a != 0 || b == 2) ? 1 : 0;
cur = 0;
for (int i = head[ind]; i != -1; i = edge[i].next_e){
int ind2 = edge[i].to;
if (ind2 != fa[ind]){
cur += min(DP(ind2, 0, a, state), DP(ind2, 1, a, 1));
}
}
ans = min(ans,cur);
}
if (a == 1) ans += c1;
if (a == 2) ans += c2;
dp[ind][a][b][c] = ans;
return ans;
}
void Deal(){
Init();
cout << min(min(DP(1, 0, 0, 1), DP(1, 1, 0, 1)), DP(1, 2, 0, 1)) << endl;
}
};
int main(){
Solve a;
while (cin >> a.n >> a.c1 >> a.c2){
if (a.n == 0 && a.c1 == 0 && a.c2 == 0) break;
a.Deal();
}
return 0;
}