算法训练 摆动序列
时间限制:1.0s 内存限制:512.0MB
问题描述
如果一个序列满足下面的性质,我们就将它称为摆动序列:
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,请求出满足上面要求的序列的个数。
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
这道题的思路很直观,从1开始到k去找满足条件的数,
1.满足两两不相等,采用记忆化搜索,用visit[i]=1来记录之前已经遍历过的数;(别忘了在递归结束后将visit[i]置零,因为在搜索下一个数的时候这个数还没有被访问)
2.满足和前两个数比较,函数传参时传递前两个数,当(i>last&&i>last_last)||(i<last&&i<last_last)时继续找下一个数。
3.cnt变量用来存放要求的序列个数。代码如下:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxsize=10000;
int k;
int visit[25]={0};
int cnt=0;//存放要求的序列个数
void dp(int last,int last_last)//传递上一个和上上个数
{
int i,j;
if(!last)//初始化条件,让序列的个数等于2
{
for(i=1;i<=k;i++)
{
visit[i]=1;
for(j=1;j<=k;j++)
{
if(!visit[j])
{
visit[j]=1;
cnt++;
dp(j,i);
visit[j]=0;
}
}
visit[i]=0;
}
}
else
{
for(i=1;i<=k;i++)
{
if(visit[i]||(i>last&&i>last_last)||(i<last&&i<last_last)) continue;//如果不满足条件继续找下一个数
else
{
visit[i]=1; //将该数置为已访问
cnt++;
dp(i,last);
visit[i]=0; //用完清零
}
}
}
return;
}
int main()
{
cin>>k;
dp(0,0);//传参0,使函数满足初始条件
cout<<cnt;
return 0;
}