2012 Multi-University Training Contest 5
Capturing a country
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Ant and Bob two army want to capture a country. The country is consist of N cities. To capture the city i, it takes Ant A[i] minutes, and Bob needs B[i] minutes to capture city i. Due to the similarity of neighboring cities, If the city i and j are neighboring cities, if Ant has captured city i, then the time for Ant to capture city j is A[j]/2. Of course if Ant has captured city j, then the time for Ant to capture city i is A[i]/2. It is the same for Bob. We define the total time to capture a country be the time to capture city 1 + the time to capture city 2 + ... + the time to capture city N. Now we want to know the minimal total time.
For simplicity, we assume that there is only one path to go from one city to another city.
Input
The first line contains a integer N(0<N<100), which is the number of cities.Then following N lines describe A[1], A[2], …, A[N];Then following N lines describe B[1], B[2], …, B[N];Next comes N-1 lines, each contains two integers x, y, meaning that city x and city y are neighboring.
Output
Just output the minimal total time in a single line.
Sample Input
3
1 2 5
3 8 1
1 2
1 3
Sample Output
3
=====================================================================================================
显然题中给图的是一颗树。问题可以抽象成对树的每个点都染色,有两中颜色可以选择。
我们可以知道,如果某一个连通的点集染的是同一种颜色,则这个集合中只要而且必须有一个点取完整的费用,其他的点都只需要对应费用的一半。
状态:dp[i][j][k] (0 <= i <= n, 0<=j<=1, 0 <= k <= 1) 表示以i为根的子树的费用,其中i节点被染成了第j种颜色,且子树中与i染成同一种颜色的与i连通的点集有k个点选取了完整的费用。
若选取1为根节点,则最后需要的结果为: min(dp[1][0][1], dp[1][1][1]}。
状态转移方程:
v为i节点的儿子节点。令 s[j] = sum{min(dp[v][j][0], dp[v][1-j][1])}, t[j] = min{dp[v][j][1] - min(dp[v][j][0], dp[v][1-j][1])};
dp[i][j][0] = cost[i][j]/2 + s[j];
dp[i][j][1] = min(cost[i][j] + s[j], cost[i][j]/2 + s[j] + t[j]);
======================================================================================================
其中,s[j]可以理解为i节点被j攻占时,它的所有儿子节点所花费的最小时间(此时子树中与i联通的点均话费一半费用,也就是还没有“取完整费用的点”)。
t[j]可以理解为i节点被j攻占时,以它所有儿子节点为根的子树中,从全部不取完整费用到有一个取完整费用的最小改变。
WA到死的注意有多组数据
======================================================================================================
#include <stdio.h>
#define MAXSIZE 105
#define MAXN 2147483646
int cost[MAXSIZE][2], n, dp[MAXSIZE][2][2];
bool pic[MAXSIZE][MAXSIZE], exist[MAXSIZE];
void readin()
{
int i, j, x, y;
for (i = 1; i <= n; ++i)
for (j = 1; j <= n; ++j) pic[i][j] = false;
for (i = 1; i <= n; ++i) scanf("%d", &cost[i][0]);
for (i = 1; i <= n; ++i) scanf("%d", &cost[i][1]);
for (i = 1; i <= n-1; ++i)
{
scanf("%d %d", &x, &y);
pic[x][y] = pic[y][x] = true;
}
}
int min(int x, int y)
{
if (x < y) return x;
else return y;
}
int dfs(int x)
{
int i, j, k, s[2], det[2];
bool flag = false;
exist[x] = true;
s[0] = s[1] = 0;
det[0] = det[1] = MAXN;
for (i = 1; i <= n; ++i)
{
if (exist[i] || !pic[x][i]) continue;
flag = true;
dfs(i);
for (j = 0; j <= 1; ++j)
{
s[j] += min(dp[i][j][0], dp[i][1-j][1]);
det[j] = min(det[j], dp[i][j][1]-min(dp[i][j][0], dp[i][1-j][1]));
}
}
if (!flag)
{
for (j = 0; j <= 1; ++j)
{
dp[x][j][0] = cost[x][j]/2;
dp[x][j][1] = cost[x][j];
}
return 0;
}
for (j = 0; j <= 1; ++j)
{
dp[x][j][0] = cost[x][j]/2+s[j];
dp[x][j][1] = min(cost[x][j]+s[j], cost[x][j]/2+s[j]+det[j]);
}
}
void solve()
{
int i;
for (i = 1; i <= n; ++i)
{
dp[i][1][1] = dp[i][1][0] = dp[i][0][1] = dp[i][0][0] = 0;
exist[i] = false;
}
dfs(1);
printf("%d\n", min(dp[1][0][1], dp[1][1][1]));
}
int main()
{
while (scanf("%d", &n) != EOF)
{
readin();
solve();
}
}