动态规划之LIS && ZigZag && BadNeighbors

题目背景

  1. 第一个LIS,最长非递减序列,这个大家应该很熟悉了吧。不用具体叙述。
  2. 第二个是TopCoder中的题目,附上网址,请点击我

理由

为什么将两者结合一起,主要是因为,所用的方法是在本质上是一样的。
首先说一下题目特征:

  • 首先都是在一维的层次上,属于初级递推公式
  • 都是以数组a[]作为输入,阶段的划分是以离散时间作为节点,在这两个程序中,我用的都是dp[]作为递推的结果记录,记录每个节点的最长纪录,但是最后的结果取所有记录的最大值
  • 属于离散随机的动态规划,离散指的是时间,随机指的是决策过程
  • 都是从bottom-up策略
  • 边界从最开始给出
  • 状态变量就是每个阶段的状态值,在这里是每个阶段的最优的状态变量
  • 区别:第一个用了一个dp[]就可以完成工作;第二个由于题目的要求,需要增加结构描述,完全是为了方便,第二个就用flag[]记录了,在另一层次的阶段的状态
  • 决策集合就是在节点之前的都可以作为决策集合,但是可以减少决策集合的数量,通过强约束条件,如第二个题目temp*flag[i]<=0 && dp[i] < dp[j+1] + 1
  • 第二题我用了三种方法进行推演,由于第一种特别的麻烦,而且很不容易想,所以有了第二个版本,但是第二个版本也是不容易演算,所以有了第三个版本;改进的策略就是将一些特判的东西进行一般化,用一个一般化的公式就可以算出,就像阶段策略一样,阶段是为了解决问题而产生的一个像生物进化的东西,随着每次演化到下一阶段,则更接近我们寻求的结果。
    直接写就无法显示后面的文字,所以直接贴图
  • 这个程序需要注意的就是初始状态如何与一般状态组合起来;技巧:其实如果数组中出现相同的值,其实可以自动忽略,因为不会起任何的作用,我的前两个程序就是没有考虑到,以为不用忽略,最后一个也是研究了国外的大神代码才看出来的,下面把他的代码和网址贴出来:
int longestZigZag( vector <int> sequence ) 
{
    int n = sequence.size();
    vector <int> dp (n, 1);
    vector <int> dif (n, 0);
    int temp;
    for (int i = 1; i < n; i++)
        for (int j = 0; j < i; j++)
        {
            temp = sequence[i] - sequence[j];
            if (temp != 0 && temp*dif[j] <= 0 && dp[j] + 1 > dp[i])
            {                  
                dp[i] = dp[j] + 1;
                dif[i] = temp;
            }
        }
    sort (dp.begin(), dp.end());
    return dp[n-1];
}

网址

BadNeighbors

题目网址

先说一下思路:
刚看到题目的时候,以为就和ZigZag思路一样的,所以就直接省略了思考DP的前面步骤,直接写出来了递推公式,最后运行case,发现{ 1, 2, 3, 4, 5, 1, 2, 3, 4, 5 }无论如何得出结果都是15,经过仔细观察还是发现了题目的tricky,因为题目要求的是Circle型算法,而我只是考虑了StraightLine型。
递归公式1:
a[]为输入串
定义dp[i]为以当前阶段以a[i]为结尾的最大的捐赠


dp(i)={a[0],max{dp[j]+a[i]},if i = 0if i != 0 && j < i && j%n != (i-1)%n)


这个dp相对有点麻烦,对于这个问题,因为最后求最大的不是最后一个dp[n-1], 下面会有改进的递推公式。
KeyPoints: 因为这还只是个StraightLine型,为了变成Circle,由于第一个元素和最后一个元素是连续的,所以用了一个技巧,就是利用忽视第一个元素算到最后一个元素的dp1[]和从第一个元素算到倒数第二个元素的dp2[],最后比较两个dp*中的最大值即可。
return max{dp1[0~n-2], dp[1~n-1]};

代码:

int maxDonations(int a[], int n)
{
    int maxValue = 0;
    int * dp1 = new int[n];
    int * dp2 = new int[n];

    dp1[0] = a[0];
    dp1[1] = (a[1]>a[0]?a[1]:a[0]);
    if (n == 2)
        return maxValue = dp1[1];
    dp2[1] = a[1];
    dp2[2] = (a[2]>a[1]?a[2]:a[1]);
    maxValue = (dp2[2]>dp1[1]?dp2[2]:dp1[1]);
    for(int i = 2; i < n -1; i++)
    {
        dp1[i] = a[i];
        for(int j = 0; j < i; j++)
        {
            if(( j%n != (i-1)%n) && dp1[j]+a[i]>dp1[i])
            {
                dp1[i] = dp1[j] + a[i];
            }
        }
        if(dp1[i] > maxValue)
        {   
            maxValue = dp1[i];
        }
    }

    for(int i = 3; i < n; i++)
    {
        dp2[i] = a[i];
        for(int j = 1; j < i; j++)
        {
            if(( j%n != (i-1)%n) && dp2[j]+a[i]>dp2[i])
            {
                dp2[i] = dp2[j] + a[i];
            }
        }
        if(dp2[i] > maxValue)
        {   
            maxValue = dp2[i];
        }
    }
    return maxValue;
}

递归公式2:
a[]为输入串
定义dp[i]为以当前阶段到a[i]的最大捐赠,可以不包括a[i],这一点与上面不同。


dp(i)=a[0],a[1],max{dp[i2]+a[i],dp[i1]},if i = 0if i = 1if i != 0 


int maxDonations(int a[], int n)
{
    int maxValue = 0;
    int * dp = new int[n];


    dp[0] = a[0];
    dp[1] = a[1]>a[0]?a[1]:a[0];
    if(n == 2)
        return maxValue = dp[1];

    for(int i = 2; i < n -1; i++)
    {
        if(a[i] + dp[i-2] > dp[i-1])
            dp[i] = a[i] + dp[i-2];
        else 
            dp[i] = dp[i-1];
    }

    maxValue = dp[n-2];
    dp[2] = a[2]>a[1]?a[2]:a[1];
    for(int i = 3; i < n; i++)
    {
        if(a[i] + dp[i-2] > dp[i-1])
            dp[i] = a[i] + dp[i-2];
        else 
            dp[i] = dp[i-1];
    }
    if(maxValue < dp[n-1])
        maxValue = dp[n-1];
    return maxValue;
}

参考网址
后续还有很多,比如说二维的动态规划,更高阶,暂时写到这……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值