hdu 4340
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4340
题意:两个人抢劫一个城市,每个人抢前一个城市相邻的城市的时候只用花费1/2的时间,求最短时间。
mark:树状dp。dp[i][j][k]代表第i个城市由第j个人抢劫,第i个城市所属子树需要完全时间的个数。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> const int M = 105; const int N = 10000000; int n,s[2][M]; int dp[M][2][2]; bool adj[M][M]; int min(int a, int b) {return a < b ? a : b;} int dfs(int i, int j, int k, int father = 0) { if(dp[i][j][k]) return dp[i][j][k]; if(k) { dp[i][j][k] = s[j][i]; for(int p = 1; p <= n; p++) if(p != father && adj[i][p]) dp[i][j][k] += min(dfs(p, j, 0, i), dfs(p, !j, 1, i)); int min1, sum; min1 = N; sum = 0; for(int p = 1; p <= n; p++) { if(p != father && adj[i][p]) { sum = dfs(p, j, 1, i); for(int q = 1; q <= n; q++) if(q != father && q != p && adj[i][q]) sum += min(dfs(q, j, 0, i), dfs(q, !j, 1, i)); min1 = min(min1, sum); } } if(!sum) return dp[i][j][k]; return dp[i][j][k] = min(dp[i][j][k], min1+s[j][i]/2); } else { dp[i][j][k] = s[j][i]/2; for(int p = 1; p <= n; p++) if(p != father && adj[i][p]) dp[i][j][k] += min(dfs(p, j, 0, i), dfs(p, !j, 1, i)); return dp[i][j][k]; } } int main() { int i,j,k; while(~scanf("%d", &n)) { for(j = 0; j < 2; j++) for(i = 1; i <= n; i++) scanf("%d", &s[j][i]); memset(adj, 0, sizeof(adj)); memset(dp, 0, sizeof(dp)); for(i = 1; i < n; i++) { scanf("%d %d", &j, &k); adj[j][k] = adj[k][j] = 1; } printf("%d\n", min(dfs(1, 0, 1), dfs(1, 1, 1))); } return 0; }