HDU4340 Capturing a country DP

自己原来写的两个维度的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\n",min(dp(1,0,1,-1),dp(1,1,1,-1)));
    }
    return 0;
}

 

posted on 2013-10-11 02:17  six_god  阅读(176)  评论(0编辑  收藏  举报

导航