2-13 标准二维表问题


问题描述

设n是一个正整数。2*n的标准二维表是由正整数1,2,…,2n组成的2*n数组,该数组的每行从左到右递增,每列从上到下递增。2*n的标准二维表全体记为Tab(n)。例如,当n=3时,tab(3)二维表如下图所示。

1 2 3
4 5 6
1 2 4
3 5 6
1 2 5
3 4 6
1 3 4
2 5 6
1 3 5
2 4 6

给定正整数n,试计算Tab(n)中2*n的标准二维表的个数。


分析

一维数组递归遍历法

将上面标准二维表从左到右从上往下看成一维数组,递归遍历,记录符合条件的情况。

进栈出栈法

1 2 3
4 5 6
1 2 3 4 5 6
0 0 0 1 1 1

如上图,先把2*n个数字排成一行来看(1~2*n 有序)。之前上表中放到第一行的数字1,2,3在下表中标记为0,放到第二行的数字4,5,6在下表中标记为1,这样就可以有一个0,1的序列,如下图(按照上面方式,将前面n=3时的所有5种标准二维表转变为一维表):

1 2 3
4 5 6
1 2 3 4 5 6
0 0 0 1 1 1
1 2 4
3 5 6
1 2 3 4 5 6
0 0 1 0 1 1
1 2 5
3 4 6
1 2 3 4 5 6
0 0 1 1 0 1
1 3 4
2 5 6
1 2 3 4 5 6
0 1 0 0 1 1
1 3 5
2 4 6
1 2 3 4 5 6
0 1 0 1 0 1

当n=3时,5种标准二维表转化成的总表如下

1 2 3 4 5 6
0 0 0 1 1 1
0 0 1 0 1 1
0 0 1 1 0 1
0 1 0 0 1 1
0 1 0 1 0 1

可见,题目要求前面的数字比后面、上面的数字比下面的数字小的问题,可以转化为,序列中每个数字前面0的个数要大于等于1的个数问题。

该问题又可以转换成进栈出栈问题。2*n个数字,进栈是0,出栈是1,且进栈出栈次数均为n,这样就可以保证输出的进栈出栈序列中每个数字前面0的个数大于等于1的个数,符合题目要求。

Catalan数法

上面方法中涉及到的 进栈出栈问题 本质上属于 Catalan数问题。因此,又可以转化为 Catalan数问题。

令h(0)=1,h(1)=1,Catalan数满足递推式[1] :
h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)h(0)(n>=2)h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)h(0)(n>=2)h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)

例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2
h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另类递推式[2] :
h(n)=h(n−1)∗(4∗n−2)/(n+1);h(n)=h(n−1)∗(4∗n−2)/(n+1);h(n)=h(n-1)*(4*n-2)/(n+1);

递推关系的解为:
h(n)=C(2n,n)/(n+1)(n=0,1,2,...)h(n)=C(2n,n)/(n+1)(n=0,1,2,...)h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

递推关系的另类解为:
h(n)=c(2n,n)−c(2n,n−1)(n=0,1,2,...)h(n)=c(2n,n)−c(2n,n−1)(n=0,1,2,...)h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)

Catalan数法(大数乘法与除法)

当输入的数n较大时,可以用 大数乘法与除法(二维数组实现) 来解决,计算Catalan数。


一维数组递归遍历法

Java

import java.util.Scanner;public class Main {private static long count = 0L;private static int[] numbers;private static int n;public static void main(String[] args) {Scanner input = new Scanner(System.in);while (true) {//还原count = 0;System.out.println("Input n: ");n = input.nextInt();System.out.println("-----------------");numbers = new int[2*n];for(int i=0;i<2*n;i++)numbers[i]=i+1;if(n==1)print();elseperm(1,2*n-2);System.out.println("Tables: "+count);System.out.println("------------------------");}}private static void perm(int start, int end){if(start==end && isOk())print();else{for(int i=start; i<=end; i++)if(start==i || (start!=i && numbers[start]!=numbers[i])){//剔除重复项swap(start,i);perm(start+1,end);swap(start,i);}}}private static void swap(int i, int j){int temp=numbers[i];numbers[i]=numbers[j];numbers[j]=temp;}private static boolean isOk(){int i,j;for(i=1;i<n;i++)//第一排比较
//            if(arr[i]<arr[i-1]||arr[i]>arr[i+n])if(numbers[i]<numbers[i-1])return false;for(++i;i<2*n;i++)//第二排比较if(numbers[i]<numbers[i-1])return false;for(j=0; j<n; j++)//列比较if(numbers[j]>numbers[j+n])return false;return true;}private static void print(){int m;count++;for(m=0; m<n; m++)System.out.print(String.format("%3d", numbers[m]));System.out.println();for(; m<2*n; m++)System.out.print(String.format("%3d", numbers[m]));System.out.println();System.out.println("-----------------");}
}

Input & Output

Input n:
1
-----------------
  1
  2
-----------------
Tables: 1
------------------------
Input n:
0
-----------------
Tables: 0
------------------------
Input n:
2
-----------------
  1  2
  3  4
-----------------
  1  3
  2  4
-----------------
Tables: 2
------------------------
Input n:
3
-----------------
  1  2  3
  4  5  6
-----------------
  1  2  4
  3  5  6
-----------------
  1  2  5
  3  4  6
-----------------
  1  3  4
  2  5  6
-----------------
  1  3  5
  2  4  6
-----------------
Tables: 5
------------------------
Input n:
4
-----------------
  1  2  3  4
  5  6  7  8
-----------------
  1  2  3  5
  4  6  7  8
-----------------
  1  2  3  6
  4  5  7  8
-----------------
  1  2  3  7
  4  5  6  8
-----------------
  1  2  4  5
  3  6  7  8
-----------------
  1  2  4  6
  3  5  7  8
-----------------
  1  2  4  7
  3  5  6  8
-----------------
  1  2  5  6
  3  4  7  8
-----------------
  1  2  5  7
  3  4  6  8
-----------------
  1  3  4  5
  2  6  7  8
-----------------
  1  3  4  6
  2  5  7  8
-----------------
  1  3  4  7
  2  5  6  8
-----------------
  1  3  5  6
  2  4  7  8
-----------------
  1  3  5  7
  2  4  6  8
-----------------
Tables: 14
------------------------
Input n: 

进栈出栈法

Java

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int i, j;int count0, count1;long count;int num;int n;while (true) {//还原初始值count = 0;n = input.nextInt();//转化为 进栈出栈的问题:2*n个数字,进栈是0,出栈是1,且进栈与出栈次数相等,均为n//B:二进制 D:十进制//当n=3时,有6个数字,最大01排列为:111111B < 1000000B = 2^(2*3)D = 2^6Dfor (i = 0; i < Math.pow(2, 2 * n); i++) {num = i;count0 = count1 = 0;for (j = 0; j < 2 * n; j++) {if (num % 2 == 0) {count0++;} else {count1++;}num = num / 2;if (count0 > count1) //二进制最后为0,表示进栈,当进栈与出栈次数相等时,前面出栈必然比进栈多一次,无进栈如何出栈,不可能。
//                    if(count1 > count0)break;}if (count1 == count0 && count0 == n)count++;}System.out.println("Tables: " + count);System.out.println("-----------------");}}
}

Input & Output

0
Tables: 1
-----------------
1
Tables: 1
-----------------
2
Tables: 2
-----------------
3
Tables: 5
-----------------
4
Tables: 14
-----------------
5
Tables: 42
-----------------
6
Tables: 132
-----------------
7
Tables: 429
-----------------
8
Tables: 1430
-----------------
9
Tables: 4862
-----------------
10
Tables: 16796
-----------------

Catalan数法

Java

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n;long catalan;while (true){n = input.nextInt();catalan = Catalan(n);System.out.println(catalan);System.out.println("--------------");}}//第一种Catalan数计算方法//h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)private static long Catalan(int n){ //0<=n<=35if(n <= 1)return 1;long[] h = new long[n+1];h[0] = h[1] = 1;for(int i = 2 ; i <= n ; i++){h[i] = 0;for(int j = 0 ; j < i ; j++)h[i] += h[j]*h[i-j-1];}return h[n];}//第二种Catalan数计算方法//h(n)=h(n-1)*(4*n-2)/(n+1)private static long Catalan2(int n){ //0<=n<=33if(n <= 1)return 1;long[] h = new long[n+1];h[0] = h[1] = 1;for(int i=2; i<=n; i++)h[i] = h[i-1]*(4*i-2)/(i+1);return h[n];}
}

Input & Output

0
1
--------------
1
1
--------------
2
2
--------------
3
5
--------------
4
14
--------------
5
42
--------------
7
429
--------------
27
69533550916004
--------------

Catalan数法(大数乘法与除法)

Java

import java.util.Scanner;public class Main {private static int MAX = 100;private static int BASE = 10000;public static void main(String[] args) {Scanner input = new Scanner(System.in);int i, j, n; //1<=n<=100int[][] a = new int[105][MAX];for (i=0; i<MAX; i++) {a[1][i] = 0;}for (i=2, a[1][MAX-1]=1; i<=100; i++) {for (j=0; j<MAX; j++)a[i][j] = a[i-1][j];multiply(a[i], MAX, 4*i-2);divide(a[i], MAX, i+1);}while (true) {n = input.nextInt();for (i = 0; i<MAX && a[n][i]==0; i++);System.out.print(a[n][i++]);for (; i<MAX; i++)System.out.print(String.format("%04d", a[n][i]));System.out.println();System.out.println("------------------");}}//大数乘法private static void multiply(int[] a, int Max, int b) {int i, array = 0;for (i=Max-1; i>=0; i--) {array += b*a[i];a[i] = array%BASE;array /= BASE;}}//大数除法private static void divide(int[] a, int Max, int b) {int i, div=0;for (i=0; i<Max; i++) {div = div*BASE+a[i];a[i] = div/b;div %= b;}}
}

Input & Output

1
1
------------------
2
2
------------------
3
5
------------------
4
14
------------------
35
3116285494907301262
------------------
100
896519947090131496687170070074100632420837521538745909320
------------------
57
26700952856774851904245220912664
------------------
24
1289904147324
------------------
68
86218923998960285726185640663701108500
------------------
79
289450081175264899454283846029490767264392230
------------------
46
8740328711533173390046320
------------------

Reference

王晓东《计算机算法设计与分析》(第3版)P47
https://blog.csdn.net/llwwlql/article/details/52920198

算法设计与分析: 2-13 标准二维表问题相关推荐

  1. 算法设计与分析——散列表/哈希表(Hash Table):直接寻址表

    分类目录:<算法设计与分析>总目录 相关文章: ·散列表/哈希表(Hash Table)(一):基础知识 ·散列表/哈希表(Hash Table)(二):直接寻址表 ·散列表/哈希表(Ha ...

  2. 【算法设计与分析】13 分治策略的设计思想

    算法中很多方法都是可以采用分治策略进行设计与优化,那么什么是分治策略?如何使用分治策略进行算法的设计与分析? 文章目录 1. 分治策略的基本思想 1.1 二分检索的设计思想 1.2 二分归并排序的设计 ...

  3. 【算法设计与分析】14 分治算法的一般描述和分析方法

    本文主要描述分治算法的一般描述和分析方法.衔接上一篇文章:[算法设计与分析]13 分治策略的设计思想 文章目录 1 分治算法的一般性描述 1.1 分支算法的时间分析 1.2 两类常见的递推方程与求解方 ...

  4. 【算法设计与分析】经典常考三十三道例题AC代码

    ❥小虾目前大三,我校在大一下开设<数据结构>这门课,大二上开了<算法设计与分析>这门课,很庆幸这两门课的上机考试总成绩一门100,一门99,最后总分也都90+.下文会给出机试的 ...

  5. 算法设计与分析(python版)-作业一

    参考教材:算法设计与分析(Python版)         作者:王秋芬 1 . 容易 (4分)2 n=O(100n ^2) 错误 2 . 容易 (3分)10=θ(log10) 正确 3 . 容易 ( ...

  6. 计算机算法设计与分析考试题,《计算机算法设计与分析》习题及答案

    <计算机算法设计与分析>习题及答案 一.选择题 1.二分搜索算法是利用( A )实现的算法. A.分治策略 B.动态规划法 C.贪心法 D.回溯法 2.下列不是动态规划算法基本步骤的是( ...

  7. 循环赛日程表非递归Java_王晓东《算法设计与分析》课件.ppt

    <王晓东<算法设计与分析>课件.ppt>由会员分享,可在线阅读,更多相关<王晓东<算法设计与分析>课件.ppt(356页珍藏版)>请在人人文库网上搜索. ...

  8. C++算法设计与分析课后习题(第三章)

    C++算法设计与分析课后习题[第三章] 前言 一.求2+22+222+2222+...+22...(n个2)...22(精确计算) 变量解释 运行截图 二.编写一个算法,其功能是给一维数组a输入任意6 ...

  9. Python 算法设计与分析 投资问题

    Python 算法设计与分析 投资问题 投资问题 题目:设有m元钱,n项投资,函数fi(x)表示将x元投入第i项项目所产生的效益,i=1,2,3,-,n.问:如何分配这m元钱,使得投资的总效益最高? ...

  10. 算法设计与分析: 5-22 魔方(Rubik's Cube)问题

    5-22 魔方(Rubik's Cube)问题 问题描述 3×3×33×3×33\times3\times3 魔方的构造如图所示.图中英文字母 U,L,F,R,B,D 分别表示魔方的 6 个面中的上面 ...

最新文章

  1. Streams:深入理解Redis5.0新特性
  2. 大学计算机专业全英文论文,计算机专业大学生英文简历模板
  3. C/C++对编程的重要性!其他编程语言都是弟弟!
  4. 苹果CMSV10绿色毛毛虫主题模板
  5. 首批拟科创板IPO名单今日揭晓!
  6. Apache MiNa 2 学习笔记
  7. sklearn.metrics.roc_curve使用说明
  8. pyhive、pyspark配置
  9. 如何新建PDF文件?新建PDF文件教程来了
  10. 灵活运用用第3方软件把“SWF”变回“FLA”
  11. 基于PHP+Web+Mysql的在线问卷调查系统
  12. win10计算机安全模式怎么,Win10进入安全模式的多种方法
  13. [Linux] SPI 设备驱动模型(以 Ad714x CapTouch 驱动分析)
  14. 干货分享 | B站SLO由失败转成功,B站SRE做对了什么?
  15. 第1讲 样本空间 随机事件
  16. 使用jsoup入门java爬虫 案例
  17. 算法编程例题——枚举法
  18. android图片放大失真,Android中解决图片文字放大失真的问题
  19. python实现ping工具
  20. web 弹出框 类似 android的toast的信息提示

热门文章

  1. spring批量写入mysql数据库_spring boot 向数据库写入海量数据
  2. ecshop+ectouch LANP伪静态
  3. 1114 Family Property (25 point(s)) PAT甲级
  4. 普乐郡——回乐县(城市记忆7)
  5. 问题adb remount提示Devices Locked
  6. A品牌电动车全国营销方案
  7. mybatis PageHelper.startPage出现limit错误
  8. 细粒度粗粒度_粗粒度基准
  9. 什么是服务器防护,什么是硬防?什么是软防?
  10. 网络流量分析工具六大必备功能