Capturing a country
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 380 Accepted Submission(s): 164
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.
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
Source
Recommend
zhuyuanchen520
终于把这道题的题解看明白了,,自己推了好长时间,又看了好长时间,汗。。。。。。。
题意: 两个人进攻n个城市,这n个城市构成一棵树,可以任意选择一个点开始,攻击已被自己攻击过的点的相邻点,
时间可以减半,两个人的攻击时间不一,两个人可以同时进行攻击。
看得是官方解题报告;
状态:dp[i][j][k] (0 <= i <= n, 0<=j<=1, 0 <= k <= 1) 表示以 i 为根的子树的费用,其中i节点被染成了第j种颜色,且子树中与i染成同一种颜色的与i连通的点集有k个点选取了完整的费用
那么 我们就可以得到 状态转移方程;
1:dp[ i ][ j ][ 0 ] = (所有以 i 为跟的 子树最小花费 的和 ) s + a[j][i]/2;
2:s = 求和 min(dp[ v ][j][0], dp[v][ 1 - j][1]) v 为 i 的子节点 ;理解:因为 在 1 中 k 值为 0 所以 与 i 连通的点 都没有取到 完整的值 及 其 子树的 k 值也为 0 ;因为 在 1 中 根节点 的颜色是 j (其子节点 必和其连通),所以,其子树中若要 然 其他的颜色 必有 第一个染 其他颜色的 节点 所以 1 - j 的 k 值 为 1;
3: dp[i][j][1] = min(cost[i][j] + S, cost[i][j]/2 + S + det);
det = min{dp[v][j][1] - min(dp[v][j][0], dp[v][1-j][1])};
若 和根节点 连通的(包括根节点本身)含有 第一个 染色 为 j 的节点 ,那么这个节点 要么是 根节点 本身 ,要么 在根节点的子树中,
若为 根节点 则 dp[ i][j ][1] = cost[i][j] + s (所有以 i 为跟的 子树最小花费 的和 ) ;
若在根节点的子树中 ,那么这个 节点 要求得必 是 子树中 花费最小的 det 就表示 这个节点的费用的 1/2 假设这个点在 以节点 v 为跟的子树中 (v是 i 的子节点)
det = dp[v][j][1] - 这棵子树的最小值 ;这棵子树的最小值为 min(dp[v][j][0], dp[v][1-j][1]) 然后 我们 枚举所有的子树 找到 最小的det 就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<set> 6 #include<map> 7 #include<queue> 8 #include<vector> 9 #include<string> 10 #define Min(a,b) a<b?a:b 11 #define Max(a,b) a>b?a:b 12 #define CL(a,num) memset(a,num,sizeof(a)); 13 #define maxn 205 14 #define inf 9999999 15 #define mx 1<<60 16 using namespace std; 17 vector<int>g[maxn]; 18 int dp[maxn][2][2],a[2][maxn],vis[maxn]; 19 void dfs(int k) 20 { 21 int i,j; 22 int len = g[k].size(); 23 if( len == 0)// 为叶子节点 24 { 25 dp[k][0][0] = a[0][k]/2; 26 dp[k][0][1] = a[0][k]; 27 dp[k][1][0] = a[1][k]/2; 28 dp[k][1][1] = a[1][k]; 29 30 31 32 return ; 33 } 34 35 36 for( i = 0; i < len ;++i) 37 dfs(g[k][i]) ; 38 39 for( i = 0;i < 2; ++i) 40 { 41 int sum = 0,det = inf ,tmp; 42 for( j = 0; j < len ;++j) 43 { 44 int w = g[k][j]; 45 tmp = min(dp[w][i][0],dp[w][1 - i][1]); 46 47 48 sum +=tmp; 49 50 det = min(det,dp[w][i][1] - tmp); 51 52 53 } 54 dp[k][i][0] = sum + a[i][k]/2; 55 dp[k][i][1] = min(a[i][k] + sum ,a[i][k]/2 + sum + det); 56 } 57 58 59 60 } 61 int main() 62 { 63 //freopen("data.in","r",stdin); 64 int n, i, j,x,y,root; 65 while(scanf("%d",&n)!=EOF) 66 { 67 for(j = 0; j < 2 ;++j) 68 { 69 for( i = 1; i <= n ;++i ) 70 scanf("%d",&a[j][i]); 71 } 72 73 74 CL(vis,0); 75 for(i = 0;i <= n;i++)g[i].clear(); 76 for(i = 0; i < n - 1 ;++i) 77 { 78 scanf("%d%d",&x,&y); 79 if( i ==0) root = x;//建的图是有向图,对解决问题没有影响,树形dp 就是 这样 80 if(!vis[y]) 81 { 82 g[x].push_back(y); 83 vis[x] = 1; 84 } 85 else g[y].push_back(x); 86 87 } 88 CL(dp,0); 89 dfs(root); 90 int t1 = dp[root][0][1]; 91 int t2 = dp[root][1][1]; 92 93 printf("%d\n",min(t1,t2)); 94 } 95 96 }