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

来源:互联网 发布:淘宝主图背景图模板 编辑:程序博客网 时间:2024/06/07 19:34

题目背景

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

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

0 0