集合划分问题

问题描述:
n个元素的集合{1,2,, n }可以划分为若干个非空子集。例如,当n=4 时,集合{1,2,3,4}可以划分为15 个不同的非空子集如下:
{{1},{2},{3},{4}},
{{1,2},{3},{4}},
{{1,3},{2},{4}},
{{1,4},{2},{3}},
{{2,3},{1},{4}},
{{2,4},{1},{3}},
{{3,4},{1},{2}},
{{1,2},{3,4}},
{{1,3},{2,4}},
{{1,4},{2,3}},
{{1,2,3},{4}},
{{1,2,4},{3}},
{{1,3,4},{2}},
{{2,3,4},{1}},
{{1,2,3,4}}

给定正整数n,计算出n个元素的集合{1,2,, n }可以划分为多少个不同的非空子集。 

 所求的是Bell 数 满足递推公式 B(n) =         

所以这道题实际求第二类Stirling数  S(n,m)

解决思想:

1.  若 m == 1    则S(n,m) = 1;    ( n >= 0 )

2.  若 m == 0    则S(n,m) = 0;    ( n >= 1  )

3.  若 n == m   则S(n,m) = 1;  

4 . 若非以上3中情况 则:

     (1)  已知前S(n-1,m)的解决方案 , 第n个数可以向分出来的m个非空子集中的每一个任意添加进去  共有m*S(n-1,m)方法

     (2) 前n-1个数已经划分成 m-1  剩余第n个数单独作为一个非空子集添加进去  共有S(n-1,m-1)种方法

#include <iostream>
using namespace std;


int f( int n , int m ){

	if( n == m && n >= 0 )
		return 1;
	if( n >=1 && m == 0 )
		return 0;
	else
		return m*f(n-1,m)+f(n-1,m-1);
}
//Bell数
int main()
{
	int n;
	cin >> n;
	int sum = 0;
	for( int i = 1 ; i <= n ; i ++ ){
		//n次循环第二类Stirling数 
		sum += f(n,i);
	}
	cout << sum << endl;
	return 0;
}

对于递归中数据量为n 的时候    一般情况下写出的递归公式里面一定含有n  或者有其他题目中的参数  例如此题中的m 

递归最重要的思想: 至顶向下  假设已知前n-1时的解决方案  有了第n-1是的解决方案 才能求第n个 。  要求第n个时  可能有多种情况(每一种情况都能列出一个递归公式) 最后将多种情况的结果相加即最终答案   所谓的终止条件即:  当递归回溯到了人脑可以算出的小数据量的时候,  "例如" 当n到了1  那么可以知道n=2时的结果 知道2的结果可求3  继而递推到n。


这里面的回溯和搜索里面的回溯虽然名字相同 但是意义略有不同  搜索里面的回溯一般是一种不断去尝试的过程 例如N皇后问题 一遍一遍的去尝试 尝试失败就回来换个方向尝试  直到找出答案。

而递归中的回溯  更像一种要得到那种终止条件不得已的将问题规模缩小  当得到答案后  再一层一层扩大直到得出最终答案。


递归的两种结题技巧:

1.   回溯到底得到临界条件 利用临界条件递推到  规模为n的为题。  例如:

 int find(int x) //查找根结点  
    {  
        int temp;  
        if(x == p[x].pre)  
            return x;  
        temp = p[x].pre; //路径压缩  
        p[x].pre = find(temp);  
        p[x].relation = (p[x].relation + p[temp].relation) % 3; //关系域更新  
        return p[x].pre; //根结点  
    }  

这是一段带权并查集的路径压缩算法。    在这段代码中分为两部分, find的函数中间截止  以上回溯,以下递推  画图即可理解。

2. 在回溯的同时解决问题,  可能会不断的进入临界条件继而返回,例如图的遍历,  但是图的遍历更像一种 一边回溯一边递推一边求解三者同时进行的思维模式。   这里的递推没有具体值  是状态量。   例子代码后粘。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值