题目背景
- 第一个LIS,最长非递减序列,这个大家应该很熟悉了吧。不用具体叙述。
- 第二个是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[i−2]+a[i],dp[i−1]},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;
}
参考网址
后续还有很多,比如说二维的动态规划,更高阶,暂时写到这……