• 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;
    }
    

      

  • 相关阅读:
    图的最大匹配算法
    二分图的最小顶点覆盖 最大独立集 最大团
    后缀数组:倍增法和DC3的简单理解
    后缀自动机浅析
    微积分学习笔记一:极限 导数 微分
    微积分学习笔记二
    微积分学习笔记三:定积分
    微积分学习笔记四:空间向量基础
    微积分学习笔记五:多元函数微积分
    程序员之路--回顾2015,展望2016
  • 原文地址:https://www.cnblogs.com/liulangye/p/2628673.html
Copyright © 2020-2023  润新知