• 算法注意---1、取用数据之前一定要保证数据存在


    算法注意---1、取用数据之前一定要保证数据存在

    一、总结

    一句话总结:

    动态规划中,f[j]=f[j] + f[j-w[i]]结构,肯定要保证j-w[i]>=0,也就是取数据之前,一定要保证数据是存在的

    1、算法里面常常描述的状态是什么意思?

    |||-being

    (比如初始状态、中间状态、结束状态)
    (又比如枚举条件里面的可预先确定每个状态的元素个数)

    |||-end

    状态可以看做要求的结果,就像x+y=z里面的z,z==0就是初始状态,z=比如100就是结束状态,那么z==50就是中间状态

    2、枚举法的条件(不必深究)?

    1、【等式可写:能进行if判断】:可预先确定每个状态的元素个数。如百钱买百鸡,3文钱一只鸡的状态元素可预先确定。
    2、【循环可做:能写for】:状态元素之间必须为一个连续的值域,方便一一枚举。

    可预先确定每个状态的元素个数。如百钱买百鸡,3文钱一只鸡的状态元素可预先确定。
    状态元素之间必须为一个连续的值域,方便一一枚举。如果值域为实数级,每两个值之间有无穷个数,这就不能枚举出所有可能的值。
    对于满足以上两个条件的问题,采用穷举法时,可以先确定枚举对象、枚举范围和判定条件,再一一枚举所有可能的解,验证是否是问题的解。


    3、枚举法感觉差了点什么?

    枚举法要是差了点,就是差的枚举法敲代码技巧:也就是 枚举变量、枚举范围、枚举判断条件


    枚举变量:
    枚举范围:
    枚举判断条件:

    4、枚举法做题除了枚举法敲代码技巧,还差一点,就是算法步骤?

    算法、算法步骤、算法注意点(这里就是枚举法敲代码技巧)缺一不可,有这三个东西,代码非常好敲,不容易出错

    5、动态规划中,f[j]=f[j] + f[j-w[i]]结构,肯定要保证j-w[i]>=0?

    也就是取数据之前,一定要保证数据是存在的

    6、动态规划填表时,下一行要复制上一行的数据,比如f[i][j]=f[i-1][j] + f[i-1][j-w[i]]中,注意点是什么?

    不仅要保证j-w[i]>=0的时候复制数据,还要保证j-w[i]小于0的时候复制数据
    //2、做动态规划
    for(int i=0;i<=1000;i++) f[i][0]=1;
    for(int i=1;i<=num;i++){
        for(int j=1;j<=1000;j++){
            //填表下一行的数据要复制上一行的数据
            if(j-w[i]>=0)
            f[i][j]=f[i-1][j] + f[i-1][j-w[i]];
            else 
            f[i][j]=f[i-1][j];
        }
    }

    7、序列转换成循环,其中的变化的关键是什么,比如序列1 1 2 3 3 5 10 20转换成循环2(1g) 1(2g) 2(3g) 1 1 1?

    准确点来说,就是中间加了一层循环来刷表,也就是增加一个物品刷一次表
    dp的转移由f(n-1)=>f(n)【if(j-w[i]) f[j]=f[j-w[i]]】变成了f(n)=>f(n+1)【if(dp[k]) dp[k+b[i]]=1】,因为转成循环的时候,循环的语义变成每增加一个物品怎样怎样
    dp的转移并没有改变
    for(int i=1;i<=6;i++)
        for(int j=1;j<=a[i];j++)//第i种砝码有a[i]个
            for(int k=mx;k>=0;k--)
                if(dp[k]==true)
                    dp[k+b[i]]=true;//标记

    8、序列转换成循环,敲代码的一个注意点是什么,比如序列1 1 2 3 3 5 10 20转换成循环2(1g) 1(2g) 2(3g) 1 1 1?

    【起始条件和终止条件】:因为减变成了加,所以循环刷表的起始和终止条件就变了,这里一定要注意一下,否则可能因为找不到初始条件而发生填表错误
    dp的转移由f(n-1)=>f(n)【if(j-w[i]) f[j]=f[j-w[i]]】变成了f(n)=>f(n+1)【if(dp[k]) dp[k+b[i]]=1】,因为转成循环的时候,循环的语义变成每增加一个物品怎样怎样
    准确点来说,就是中间加了一层循环来刷表,也就是增加一个物品刷一次表
    //2、做动态规划
    f[0] = 1;
    for (int i = 1; i <= 6; i++)
    {
        for (int k = 1; k <= n[i]; k++)
        {
            //这里要大于等于零,要不然永远跑不到f[0]这里来,初始化的数据就没用了,永远是0 
            for (int j = 1000; j >= 0; j--)
            {
                //填表下一行的数据要复制上一行的数据
                if (f[j])
                    f[j + b[i]] = 1;
            }
        }
    }

    9、动态规划中,中间层循环的真正意义(动态规划状态转移方程中没有用到的变量)?

    让表再刷一遍(比如下面实例中背包问题的一维的表)
    //2、做动态规划
    for (int i = 0; i <= 1000; i++)
        f[i][0] = 1;
    for (int i = 1; i <= 6; i++)//遍历六种砝码
    {
        for (int k = 1; k <= n[i]; k++)//依次增加砝码的个数
        {
            //其实也就是让下面的表再刷一遍
            for (int j = 1; j <= 1000; j++)
            {
                //填表下一行的数据要复制上一行的数据
                
                if (j - b[i] >= 0)
                    f[i][j] = f[i - 1][j] | f[i - 1][j - b[i]];
                else
                    f[i][j] = f[i - 1][j];
            }
        }
    }

    10、用二维表来刷无限背包的易错点?

    中间k层循环的意义就是不断的刷表,而我希望的是不断的拿我更新好的这一行来刷这一行,而下面的代码却是总是拿上一行来刷这一行,所以肯定出问题
    这就是背包问题里面的无限背包问题
    
    for (int i = 1; i <= 6; i++)//遍历六种砝码
    {
        for (int k = 1; k <= n[i]; k++)//依次增加砝码的个数
        {
            //其实也就是让下面的表再刷一遍
            for (int j = 1; j <= 1000; j++)
            {
                //填表下一行的数据要复制上一行的数据
                //出错的原因就是我根本就是希望拿前面的值来耍后面的值
                //而这里总是拿上一行的值来刷的,肯定就有问题
                if (j - b[i] >= 0)
                    f[i][j] = f[i - 1][j] || f[i - 1][j - b[i]];
                else
                    f[i][j] = f[i - 1][j];
            }
        }
    }

    二、内容在总结中

    博客对应课程的视频位置:

     
  • 相关阅读:
    【CF1172E】Nauuo and ODT(Link-Cut Tree)
    【UOJ#242】【UR#16】破坏蛋糕(计算几何)
    【CF528E】Triangles 3000(计算几何)
    【CF1053E】Euler tour
    【CodeChef】Find a special connected block
    【CF933E】A Preponderant Reunion(动态规划)
    【CF704D】Captain America(上下界网络流)
    【BZOJ4823】[CQOI2017]老C的方块(网络流)
    【LOJ#2162】【POI2011】Garbage(欧拉回路)
    【CF241E】Flights(差分约束)
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/13028100.html
Copyright © 2020-2023  润新知