问题描述:
设n是一个正整数,2*n的二维表是由正整数1,2,…,2n组成的2*n数组,该数组的每行从左到右递增,每列从上到下递增。这样的数组为标准二维表。
输入一个整数n(0<n<=10^3)
输出标准二维表的个数,由于结果较大,输出结果要模除1000000007。
输入n
输出一个整数
样例输入
3
样例输出
5
递归的代码:
利用递归时,我们基于入栈和出栈的思想来解决问题:
(1)如果元素出现在第一个位置,则必定是:元素1先入栈、出栈;然后再对其他n-1个元素进行入栈和出栈,如果用h(n)来表示对n个数进行出栈和入栈的次数,则此种情况对应的排列数为h(n-1)。
(2)如果1出现在第二个位置,则此时的状态必然是:元素1和2入栈,元素2出栈,元素1出栈,后面的n-2个元素出入栈。此时的排列数为h(1)h(n-2),此时h(1)代表对元素2出栈和入栈的情况;
(3)如果1出现在第3个位置,则必然是先将1入栈,再后将2、3入栈,再将2、3出栈;然后再将1出栈,最后将其他的n-3个元素进行出栈和入栈。此时的排列数为h(2)h(n-3),其中h(2)代表对2和3两个元素进行入栈和出栈的情况。
......
(4)如果1出现在最后的位置,则必然是1入栈,再后将后面的n-1个数入栈和出栈,最后将1出栈。此时的排列数为h(n-1)。
基于加法原则,对n个元素进行出栈和入栈的排列情况数为:
h(n)=h(n-1)+h(1)h(n-2)+...+h(n-1)
如果规定h(0)=1,则第一种情况h(n-1)可以写为h(0)h(n-1)。因此如果假设完成n次出栈和入栈的次数为h(n),则有
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)
其中初始条件为h(0)=1。
还要考虑输出结果不要整形溢出,所以:下面的代码
#include<stdio.h>
long long NumST[10000];
void PER()
{
int i,j;
NumST[0]=1;
long long sumCount;
for(i=1;i<1001;i++)
{
sumCount=0;
for(j=0;j<i;j++)
{
sumCount+=NumST[j]*NumST[i-1-j];
sumCount=sumCount%1000000007;
}
NumST[i]=sumCount;
}
}
int main()
{
int n;
scanf("%d",&n);
PER();
printf("%lld",NumST[n]);
return 0;
}
暴力搜索的代码:
运用暴力搜索时,我们基于任意时刻0的个数比1多的原理(总的0的个数是与1相等的),将这2n个数字的位置设定为在上面就是0,在下边就是1,构造一个二进制字符串来表示这些数字的位置情况,将每一种情况下的结果保存进一个数组,统计数组中0和1的个数,进行判断,即可。
#include <stdio.h>
#include <math.h>
int judge(int a[], int n){
//判断字符串是否符合条件,0和1的个数相同,任意时刻0的个数比1应多
int sum0, sum1;
int i;
sum0=sum1=0;
for(i=0;i<n;i++){
if(a[i]==0) sum0++;
else sum1++;
if(sum0<sum1)
return 0;
}
if(sum0!=sum1)
return 0;
return 1;
}
int main()
{
int n,i,count=0;
int *table;
int num,temp;
scanf("%d",&n);
table= new int[2*n-1];
for(num=0;num<(int)pow(2.,2*n);num++){
temp=num;
for(i=0;i<2*n;i++){
table[i]=temp%2;
temp/=2;
}
if(judge(table,2*n)){
count++;
}
}
printf("%d\n",count);
return 0;
}