hdu 4340 Capturing a country

http://acm.hdu.edu.cn/showproblem.php?pid=4340

树型dp 理解起来并不难但是状态有点多 比赛的时候没敢写

解题上好像是用的三维数组 有两个维大小是2 的 

自己干脆写了6个一维数组  然后6个dp函数相互调用  虽然代码有点长

但是理解方便 思路也比较清晰

对予一个子树的根节点 有6中方法

1  A从这里进攻

2  B从这里进攻

3  A攻击这里时间花一半 因为上面的相邻城市A 已经提前攻破

4  B-------------------------------------

5  A攻击这里花一半时间  因为下面的某个相邻城市已经被A提前攻破

6  B-----------------------------------

对于没种状态  向下选取攻击方法的时候 选择合适的  最恰当的

代码及其注释:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<map>

#include<cmath>

#define LL long long



using namespace std;



const int N=105;

const int M=0x3f3f3f3f;

struct node

{

    struct tt *next;

}mem[N];

struct tt

{

    int j;

    struct tt *next;

};

int ansa[N];//A 直接攻击这里 花费全部时间

int ansb[N];//B 直接攻击这里 花费全部时间

int ansa0[N];// A 攻击 一半时间  上面提前相邻的已被 A 攻破

int ansb0[N];// B 攻击 一半时间  上面提前相邻的已被 B 攻破

int ansa1[N];// A 攻击 一半时间  下面提前相邻的已被 A 攻破

int ansb1[N];// B 攻击 一半时间  下面提前相邻的已被 B 攻破

int a[N],b[N];

void build(int i,int j)

{

    struct tt *t=new tt;

    t->j=j;

    t->next=mem[i].next;

    mem[i].next=t;

}

void Dele(int n)

{

    for(int i=1;i<=n;++i)

    mem[i].next=NULL;

}

int MIN(int x,int y,int z)

{

    if(x>y)

    x=y;

    if(x>z)

    x=z;

    return x;

}

int dpb(int ,int);

int dpa0(int ,int);

int dpb0(int ,int);

int dpa1(int ,int);

int dpb1(int ,int);

int dpa(int x,int pre)

{

    if(ansa[x]!=-1)

    return ansa[x];

    ansa[x]=a[x];// A花费全部时间攻击这里

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            ansa[x]+=MIN(dpa0(t->j,x),dpb(t->j,x),dpb1(t->j,x));//再攻击下面的点 A 在攻击就可以花费一半时间  B的话就不行了

        }

        t=t->next;

    }

    return ansa[x];

}

int dpb(int x,int pre)

{

    if(ansb[x]!=-1)

    return ansb[x];

    struct tt *t=mem[x].next;

    ansb[x]=b[x];

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            ansb[x]+=MIN(dpb0(t->j,x),dpa(t->j,x),dpa1(t->j,x));

        }

        t=t->next;

    }

    return ansb[x];

}

int dpa0(int x,int pre)

{

    if(ansa0[x]!=-1)

    return ansa0[x];

    ansa0[x]=a[x]/2;// A 花费一半时间 攻击这里 上面相邻城市 A已经提前攻破

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            ansa0[x]+=MIN(dpa0(t->j,x),dpb(t->j,x),dpb1(t->j,x));//下面 A 攻击花一半时间  B的话有两种

        }

        t=t->next;

    }

    return ansa0[x];

}

int dpb0(int x,int pre)

{

    if(ansb0[x]!=-1)

    return ansb0[x];

    ansb0[x]=b[x]/2;

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            ansb0[x]+=MIN(dpb0(t->j,x),dpa(t->j,x),dpa1(t->j,x));

        }

        t=t->next;

    }

    return ansb0[x];

}

int dpa1(int x,int pre)

{

    if(ansa1[x]!=-1)

    return ansa1[x];

    int temp=a[x]/2;//A花费一半时间  下面某个相邻的城市已被提前攻破 先保存下面城市不用提前攻破的情况

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            temp+=MIN(dpa0(t->j,x),dpb(t->j,x),dpb1(t->j,x));

        }

        t=t->next;

    }

    ansa1[x]=M;

    t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            int k=MIN(dpa0(t->j,x),dpb(t->j,x),dpb1(t->j,x));

            ansa1[x]=MIN(ansa1[x],temp-k+dpa(t->j,x),temp-k+dpa1(t->j,x));//枚举下面哪个城市 是提前攻破的(提前攻破 有直接全部时间攻破 和 再把这样状态向下传递两个情况)

        }

        t=t->next;

    }

    return ansa1[x];

}

int dpb1(int x,int pre)

{

    if(ansb1[x]!=-1)

    return ansb1[x];

    int temp=b[x]/2;

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            temp+=MIN(dpb0(t->j,x),dpa(t->j,x),dpa1(t->j,x));

        }

        t=t->next;

    }

    ansb1[x]=M;

    t=mem[x].next;

    while(t!=NULL)

    {

        if(t->j!=pre)

        {

            int k=MIN(dpb0(t->j,x),dpa(t->j,x),dpa1(t->j,x));

            ansb1[x]=MIN(ansb1[x],temp-k+dpb(t->j,x),temp-k+dpb1(t->j,x));

        }

        t=t->next;

    }

    return ansb1[x];

}

int main()

{

    //freopen("data.txt","r",stdin);

    int n;

    while(scanf("%d",&n)!=EOF)

    {

        for(int i=1;i<=n;++i)

        scanf("%d",&a[i]);

        for(int i=1;i<=n;++i)

        scanf("%d",&b[i]);

        for(int i=1;i<n;++i)

        {

            int x,y;

            scanf("%d %d",&x,&y);

            build(x,y);

            build(y,x);

        }

        memset(ansa,-1,sizeof(ansa));

        memset(ansb,-1,sizeof(ansb));

        memset(ansa0,-1,sizeof(ansa0));

        memset(ansb0,-1,sizeof(ansb0));

        memset(ansa1,-1,sizeof(ansa1));

        memset(ansb1,-1,sizeof(ansb1));

        int ans=M;

        ans=MIN(ans,dpa(1,0),dpb(1,0));//从1 这个节点进行dp  只有这4 种状态  选最小的那个

        ans=MIN(ans,dpa1(1,0),dpb1(1,0));

        printf("%d\n",ans);

        Dele(n);

    }

    return 0;

}

  

你可能感兴趣的:(count)