Young Tableau问题的描述是这样的,一个由N个小方块组成的阵列(不一定要是矩形,可以是一个任意"光滑"且"单调"的组合),从1到N这N个数填入方块中,要求全部填满并且一个数只能填一个方格一次.并且满足,每个数的上方的数和左方的数比它大.求最后一共有多少种填法.比如一个4*4格子的正方形,1~16这16个数按照上述规则填入,那么一共多少种填法.
笔者根据理解,还是用程序实现了一下算了.不遍历输出所有种类的填法,只算数目而已.语言就用java,比较没挑战性,就练习一下.思想主要就一个递归:16肯定是占据左上角的格子,然后15就可以有两个选择了,对每种选择依次填下去.
笔者的解决方法,觉得可以视为一个树状展开,树的层次从上到下依次可看做16,15,14...,3,2,1. 比如填入15时可以有两个格可选,那么对目前来说就是两个叶子节点,对每一个15的填法,填14时就按照规则找到14可以填的格子作为该节点的儿子,最终要找的就是有多少个叶子节点而已.
需要根据题目的要求找到依次每个数(从16 downwards to 1)填入时有多少种可填法,填完了就将此格置位.某个格子在某个时刻是不是可填,依赖于上方和左方的格子是否已填,如果上方或者左方是边界,那么就如同已填.
代码如下:
其中
笔者根据理解,还是用程序实现了一下算了.不遍历输出所有种类的填法,只算数目而已.语言就用java,比较没挑战性,就练习一下.思想主要就一个递归:16肯定是占据左上角的格子,然后15就可以有两个选择了,对每种选择依次填下去.
笔者的解决方法,觉得可以视为一个树状展开,树的层次从上到下依次可看做16,15,14...,3,2,1. 比如填入15时可以有两个格可选,那么对目前来说就是两个叶子节点,对每一个15的填法,填14时就按照规则找到14可以填的格子作为该节点的儿子,最终要找的就是有多少个叶子节点而已.
需要根据题目的要求找到依次每个数(从16 downwards to 1)填入时有多少种可填法,填完了就将此格置位.某个格子在某个时刻是不是可填,依赖于上方和左方的格子是否已填,如果上方或者左方是边界,那么就如同已填.
代码如下:
public void find(){
boolean[][]initialMatx = generateMatx();
int nowFilling=ROW*COLUMN-1;
System.out.println(doExpend(nowFilling, initialMatx));
}
其中
private int doExpend(int nowFilling, boolean[][] nowMatx)
为递归函数,找到该节点有多少种填法后,把信息布尔矩阵复制并更新一遍,进行迭代即可.需要注意的是返回值,每个节点新增的儿子数需要减1(也就是父亲自己)才是迭代到当前的叶子节点的新增数,于是把此节点的兄弟姐妹数加上SUM(每个兄弟姐妹的儿子节点的数目-1)就是当前的叶子节点数,如果迭代完毕,到了数字1(实际上,只需要进行到数字3完成就可以了,因为2和1必定无法继续增加系统的叶子),则返回1,因为它只有自身,作为一片叶子而存在.
private int doExpend(int nowFilling, boolean[][] nowMatx) {
if(nowFilling==1){
return 1;
}
List<Grid> thisCount = findLegalGridToFill(nowMatx);
int[] ChildNumber = new int[thisCount.size()];
for (int k = 0; k < thisCount.size(); k++) {
Grid grid = thisCount.get(k);
//为每个分支复制新的matx,递归,结果累加至返回值
int stepNew = nowFilling -1;
boolean[][] thisNewMat = this.getNewMatx(nowMatx, grid.getRow(), grid.getCol());
ChildNumber[k]=doExpend(stepNew, thisNewMat);
}
int ExpandingDiff=0;
for(int ch = 0;ch<ChildNumber.length;ch++){
ExpandingDiff+=(ChildNumber[ch]-1);
}
return thisCount.size()+ExpandingDiff;
}