算法设计与分析: 2-13 标准二维表问题
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 标准二维表问题相关推荐
- 算法设计与分析——散列表/哈希表(Hash Table):直接寻址表
分类目录:<算法设计与分析>总目录 相关文章: ·散列表/哈希表(Hash Table)(一):基础知识 ·散列表/哈希表(Hash Table)(二):直接寻址表 ·散列表/哈希表(Ha ...
- 【算法设计与分析】13 分治策略的设计思想
算法中很多方法都是可以采用分治策略进行设计与优化,那么什么是分治策略?如何使用分治策略进行算法的设计与分析? 文章目录 1. 分治策略的基本思想 1.1 二分检索的设计思想 1.2 二分归并排序的设计 ...
- 【算法设计与分析】14 分治算法的一般描述和分析方法
本文主要描述分治算法的一般描述和分析方法.衔接上一篇文章:[算法设计与分析]13 分治策略的设计思想 文章目录 1 分治算法的一般性描述 1.1 分支算法的时间分析 1.2 两类常见的递推方程与求解方 ...
- 【算法设计与分析】经典常考三十三道例题AC代码
❥小虾目前大三,我校在大一下开设<数据结构>这门课,大二上开了<算法设计与分析>这门课,很庆幸这两门课的上机考试总成绩一门100,一门99,最后总分也都90+.下文会给出机试的 ...
- 算法设计与分析(python版)-作业一
参考教材:算法设计与分析(Python版) 作者:王秋芬 1 . 容易 (4分)2 n=O(100n ^2) 错误 2 . 容易 (3分)10=θ(log10) 正确 3 . 容易 ( ...
- 计算机算法设计与分析考试题,《计算机算法设计与分析》习题及答案
<计算机算法设计与分析>习题及答案 一.选择题 1.二分搜索算法是利用( A )实现的算法. A.分治策略 B.动态规划法 C.贪心法 D.回溯法 2.下列不是动态规划算法基本步骤的是( ...
- 循环赛日程表非递归Java_王晓东《算法设计与分析》课件.ppt
<王晓东<算法设计与分析>课件.ppt>由会员分享,可在线阅读,更多相关<王晓东<算法设计与分析>课件.ppt(356页珍藏版)>请在人人文库网上搜索. ...
- C++算法设计与分析课后习题(第三章)
C++算法设计与分析课后习题[第三章] 前言 一.求2+22+222+2222+...+22...(n个2)...22(精确计算) 变量解释 运行截图 二.编写一个算法,其功能是给一维数组a输入任意6 ...
- Python 算法设计与分析 投资问题
Python 算法设计与分析 投资问题 投资问题 题目:设有m元钱,n项投资,函数fi(x)表示将x元投入第i项项目所产生的效益,i=1,2,3,-,n.问:如何分配这m元钱,使得投资的总效益最高? ...
- 算法设计与分析: 5-22 魔方(Rubik's Cube)问题
5-22 魔方(Rubik's Cube)问题 问题描述 3×3×33×3×33\times3\times3 魔方的构造如图所示.图中英文字母 U,L,F,R,B,D 分别表示魔方的 6 个面中的上面 ...
最新文章
- Streams:深入理解Redis5.0新特性
- 大学计算机专业全英文论文,计算机专业大学生英文简历模板
- C/C++对编程的重要性!其他编程语言都是弟弟!
- 苹果CMSV10绿色毛毛虫主题模板
- 首批拟科创板IPO名单今日揭晓!
- Apache MiNa 2 学习笔记
- sklearn.metrics.roc_curve使用说明
- pyhive、pyspark配置
- 如何新建PDF文件?新建PDF文件教程来了
- 灵活运用用第3方软件把“SWF”变回“FLA”
- 基于PHP+Web+Mysql的在线问卷调查系统
- win10计算机安全模式怎么,Win10进入安全模式的多种方法
- [Linux] SPI 设备驱动模型(以 Ad714x CapTouch 驱动分析)
- 干货分享 | B站SLO由失败转成功,B站SRE做对了什么?
- 第1讲 样本空间 随机事件
- 使用jsoup入门java爬虫 案例
- 算法编程例题——枚举法
- android图片放大失真,Android中解决图片文字放大失真的问题
- python实现ping工具
- web 弹出框 类似 android的toast的信息提示