自己原来写的两个维度的DP有错,看了半天这个大牛的blog。http://blog.csdn.net/cyberzhg/article/details/7840922
题意:A军队和B军队要一起占领一个国家,城市和城市之间有一些双向边(但是没有环)。A军队要占领i城市需要a[i]的代价,B军队需要b[i]的代价。
若果A军队占领了i城市,i城市和j城市相邻,则A军队占领j城市只要a[i]/2的代价,B军队同理。问两个军队一起占领所有城市所需要花费的最小代价是多少。
解题过程上上述解题报告,再加几点自己的理解
f[i][0][0]表示的是以i用A军队进行进攻,且其所有选A军队的孩子选择半价的代价。
f[i][0][0] 和f[i][1][0]是一个辅助状态。
f[i][0][1]和f[i][1][1]才是正解。
对于”选择一个儿子付出代价,这个代价必须最小:min(dp[v][0][1] - min(dp[v][0][0], dp[v][1][0]));“
这个转移方程的理解要从dp[u][0][1] = min(SA + A[u], SA + A[u] / 2 + DA);来分析
SA+A[u]/2+DA=sum{min(dp[v][0][0], dp[v][1][1])}+A[u]/2+min(dp[v][0][1] - min(dp[v][0][0], dp[v][1][0]));
注意黄色表示的两个量相同。
假设min(dp[v][0][0],dp[v][1][1])= tmp[v];
则表达式可以清楚得写成SA+A[u]/2+DA=tm[1]+tmp[2]+tmp[3]+...tmp[sonSize]+min(dp[v][0][1]-tmp[j]) +A[u]/2;
=min{dp[v][0][1]+tmp[1]+tmp[2]+tmp[3]+...tmp[j-1]+tmp[j+1]+...+tmp[sonSize}+ A[u]/2;
可以理解成已知一个数列的加和sum,现在改变其中a[i]成为p。。则新的加和为sum-a[i]+p;
方程长确实比较不喜欢看。
代码实现的时候死在#define min(a,b) ((a)>(b)? (b):(a))上面了,我竟然不知道。。好吧,引以为戒。。
#include <stdio.h> #include <string.h> #define MAXN 105 #define min(a,b) ((a)>(b)? (b):(a)) int f[MAXN][2][2]; int a[MAXN]; int b[MAXN]; int map[MAXN][MAXN]; int dp(int i, int j,int k,int fa) { if (f[i][j][k] != -1) return f[i][j][k]; if (map[i][0] == 1 && fa != -1) { f[i][0][0]=a[i]/2; f[i][0][1]=a[i]; f[i][1][0]=b[i]/2; f[i][1][1]=b[i]; return f[i][j][k]; } int son; int SA=0; int SB=0,DA=1000000000,DB=1000000000; // if (i == 2) printf("!!!"); for (int p = 1; p <= map[i][0]; p++) if (map[i][p] != fa) { son=map[i][p]; SA+=min(dp(son,0,0,i),dp(son,1,1,i)); SB+=min(dp(son,1,0,i),dp(son,0,1,i)); DA=min(DA,dp(son,0,1,i)-min(dp(son,0,0,i),dp(son,1,1,i))); DB=min(DB,dp(son,1,1,i)-min(dp(son,1,0,i),dp(son,0,1,i))); } f[i][0][0]=SA+a[i]/2; f[i][1][0]=SB+b[i]/2; f[i][0][1]=min(SA+a[i],SA+a[i]/2+DA); f[i][1][1]=min(SB+b[i],SB+b[i]/2+DB); } int main() { int i,j,m,n; int x,y,k; while (scanf("%d", &n) != EOF) { for (i = 1; i <= n; i++) scanf("%d", &a[i]); for (i = 1; i <=n; i++) scanf("%d", &b[i]); memset(map,0,sizeof(map)); memset(f,-1,sizeof(f)); for (i = 1; i <n; i++) { scanf("%d%d",&x,&y); map[x][++map[x][0]]=y; map[y][++map[y][0]]=x; } printf("%d ",min(dp(1,0,1,-1),dp(1,1,1,-1))); } return 0; }