如果一个序列满足下面的性质,我们就将它称为摆动序列:
1. 序列中的所有数都是不大于k的正整数;
2. 序列中至少有两个数。
3. 序列中的数两两不相等;
4. 如果第i – 1个数比第i – 2个数大,则第i个数比第i – 2个数小;如果第i – 1个数比第i – 2个数小,则第i个数比第i – 2个数大。
比如,当k = 3时,有下面几个这样的序列:
1 2
1 3
2 1
2 1 3
2 3
2 3 1
3 1
3 2
一共有8种,给定k,请求出满足上面要求的序列的个数。
输入格式
输入包含了一个整数k。(k<=20)
输出格式
输出一个整数,表示满足要求的序列个数。
样例输入
3
样例输出
8
自己从来没有做过动态规划的题目,之前接触动态规划还是为了过算法的考试。所以说,坑总是要填的,迟早的事情,加油!
言归正传,这个题是要求满足题目的序列个数。刚开始看到这个题,我的想法是,先自己试着手动做做,看看能不能发现什么。果然被我试出来了。动态规划核心是构造一个表,根据已有的表格内容得到我们想要的结果。构造表的过程并不是一下子就成功的,期间我共想了两种方式来构造,但是后来发现第一种方式是没有办法构造表的,因为在构造的过程中发现表间元素没有什么关联,所以换个思路,用另一个方法进行构造(有点递归的意思,但是并不是递归,也就是说当前数据依靠表格的之前的数据),给大家看一下我的表格构造:
002 | 003 | 004 | 005 | 006 | 007 | 008 | |||
002 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | ||
003 | 6 | 2 | 0 | 0 | 0 | 0 | 0 | ||
004 | 12 | 8 | 2 | 0 | 0 | 0 | 0 | ||
005 | 20 | 20 | 10 | 2 | 0 | 0 | 0 | ||
006 | 30 | 40 | 30 | 12 | 2 | 0 | 0 | ||
007 | 42 | 70 | 70 | 42 | 14 | 2 | 0 | ||
008 | 56 | 112 | 140 | 112 | 56 | 16 | 2 |
通过这个表格不难发现规律。
(1)这个表格为什么从2开始呢?
因为根据题目要求,每行至少两个正整数,所以不存在0和1的情况;
(2)这个表格根据什么构成?
是根据k值的不同,来看对应情况下的可能的序列个数。举个例子:当k等于3的时候,考虑如果只有俩个数组成,可能多少种情况,如果有3个数组成,可能多少种情况。填入到表格中即可。如果学过排列组合,那不难发现彼此之间的关系,也因此得到了这个表格。
(3)有人可能通过排列组合的方式,不用构建表格就可以得到最后的结果,那还有必要建表格吗?
有必要。如果是排列组合,举例来说:k=8时,
这样也可以算出最后的结果,但是乘法比加法的运算速度慢,此外,如果这么计算,其实重复性挺大的,利用表格,相当于记录了路径,之前算的东西可以直接拿来用,不用重新进行计算,更为快捷方便!
好,给大家看一下代码,不到之处还希望大家可以批评指正:
#include<iostream>
using namespace std;
int main()
{
int k;
int a[21][21];
long result = 0;
cin>>k;
for(int i = 2; i <= k; i++)
{
a[i][i] = 2;
a[i][2] = i*(i-1);
for(int j = 3; j < i; j++)
{
a[i][j] = a[i-1][j]+a[i-1][j-1];
}
}
for(int i = 2; i <= k; i++)
{
result += a[k][i];
}
cout<<result;
return 0;
}
END。