许多问题可以转化为二叉树的遍历
包括八皇后问题,幂集问题,全排列问题,组合问题,背包问题
不信?
试试看
其实只要涉及对元素进行是否判断的问题,都可以用树来解决.(显然废话,但是很久以来没有注意到)
1 八皇后问题
就是对64个单元格进行是否判断
当"是"怕判断达到8个就再判断是否满足八皇后的条件
然后回溯
而遍历树的过程就是用递归法.
(代码只是实例,不保证可以运行)
2 幂集问题
集合{1,2,3,4,5}的全部幂集
判断每个元素分别进行取舍得到一个二叉树.遍历之即可.
3 全排列
当然这里就不是二叉树,而是多叉数了
因为要判断的是第一个位置是1 或者 2或者...
比如 对 1 2 3 4 5 进行全排
根节点下面是 1 2 3 4 5 共5个结点
然后1下面的是 2 3 4 5
3 n个数选m的组合问题
就是幂集问题嘛
只不过要判断幂集的元素个数是否为m个.
4 把n个相同的球放到m个不同的盒子中,方法有多少种?
第一个盒子可以有 a1 = 0~n个
第二个盒子... 0~ n-a1个
然后用上面的排列案例中的多叉数就可以了
5 背包问题
其实就是幂集问题啦
只不过第i层的各个节点是第i个物品的个数
所以也是一个多叉数.
可以看到
只要清楚自己的步骤和第i层的关系
一切都很明了
当然,具体问题还要具体分析,这种方法对于可以分解为yes,no或者有限个情况的问题是好解决的
但是,比如对于汉诺塔问题
就只能老实的使用递归了.
包括八皇后问题,幂集问题,全排列问题,组合问题,背包问题
不信?
试试看
其实只要涉及对元素进行是否判断的问题,都可以用树来解决.(显然废话,但是很久以来没有注意到)
1 八皇后问题
就是对64个单元格进行是否判断
当"是"怕判断达到8个就再判断是否满足八皇后的条件
然后回溯
而遍历树的过程就是用递归法.
(代码只是实例,不保证可以运行)
void
main()
{
int a [64] = {1,2 ,3 ....64};
int flag[64] = {0};
BHH(0,64,a);
}
void BHH( int i, int n, int [] a)
{
if (flag 中的元素不满足条件,包括不能在同行的类似问题,插入元素超过8个)
{return;}
if (i ==n 而且满足条件)
{ //打印 }
flag[i] = 1
BHH(i+1,n,a);
flag[i]= 0;
BHH(i+1,n,a);
}
{
int a [64] = {1,2 ,3 ....64};
int flag[64] = {0};
BHH(0,64,a);
}
void BHH( int i, int n, int [] a)
{
if (flag 中的元素不满足条件,包括不能在同行的类似问题,插入元素超过8个)
{return;}
if (i ==n 而且满足条件)
{ //打印 }
flag[i] = 1
BHH(i+1,n,a);
flag[i]= 0;
BHH(i+1,n,a);
}
2 幂集问题
集合{1,2,3,4,5}的全部幂集
判断每个元素分别进行取舍得到一个二叉树.遍历之即可.
PowerSet( i , n ,a )
//
i 表示第i 个元素,n表示元素的总共个数
{
if (i == n)
{
//打印结果,在这里只打印标记为1的
for (int t = 0 ; t < n ; t++)
if ( flag[t] == 1)
printf("%d " ,a[t]);
printf(" ");
}
//二叉树的左孩子,即"是"的情况
flag[i] = 1 ;
PowerSet (i+1,n,a);
//二叉树的右孩子,即"否"的情况
flag[i]= 0;
PowerSet(i+1,n,a)
}
// 调用
void main()
{
int a[5] = {1,2,3,4,5};
int flag[5] = {0}; //记录a中每个元素的选择情况
PowerSet(0,5,a);
}
{
if (i == n)
{
//打印结果,在这里只打印标记为1的
for (int t = 0 ; t < n ; t++)
if ( flag[t] == 1)
printf("%d " ,a[t]);
printf(" ");
}
//二叉树的左孩子,即"是"的情况
flag[i] = 1 ;
PowerSet (i+1,n,a);
//二叉树的右孩子,即"否"的情况
flag[i]= 0;
PowerSet(i+1,n,a)
}
// 调用
void main()
{
int a[5] = {1,2,3,4,5};
int flag[5] = {0}; //记录a中每个元素的选择情况
PowerSet(0,5,a);
}
3 全排列
当然这里就不是二叉树,而是多叉数了
因为要判断的是第一个位置是1 或者 2或者...
比如 对 1 2 3 4 5 进行全排
根节点下面是 1 2 3 4 5 共5个结点
然后1下面的是 2 3 4 5
void
main()
{
int a[5] = {1,2,3,4,5};
int flag[5] = 0; //记录第i个位置填入的数字在a中的下标.
Pailie(0,5,a);
}
void Pailie( int i , int n, int [] a)
{
if (i == n )
{
//打印,按照flag记录的下标的顺序打印a
}
for (a.length) //a的长度要变化,以提高效率.
{
flag[i] = a[j]
把a[j]除去,得到新的a
Pailie (i+1,n,a);
}
}
{
int a[5] = {1,2,3,4,5};
int flag[5] = 0; //记录第i个位置填入的数字在a中的下标.
Pailie(0,5,a);
}
void Pailie( int i , int n, int [] a)
{
if (i == n )
{
//打印,按照flag记录的下标的顺序打印a
}
for (a.length) //a的长度要变化,以提高效率.
{
flag[i] = a[j]
把a[j]除去,得到新的a
Pailie (i+1,n,a);
}
}
3 n个数选m的组合问题
就是幂集问题嘛
只不过要判断幂集的元素个数是否为m个.
4 把n个相同的球放到m个不同的盒子中,方法有多少种?
第一个盒子可以有 a1 = 0~n个
第二个盒子... 0~ n-a1个
然后用上面的排列案例中的多叉数就可以了
5 背包问题
其实就是幂集问题啦
只不过第i层的各个节点是第i个物品的个数
所以也是一个多叉数.
可以看到
只要清楚自己的步骤和第i层的关系
一切都很明了
当然,具体问题还要具体分析,这种方法对于可以分解为yes,no或者有限个情况的问题是好解决的
但是,比如对于汉诺塔问题
就只能老实的使用递归了.