• ybt1315 递归例题(虽然用的是递推)集合划分


    ybt1315 集合划分

    递归算法

    【题目描述】

    设S是一个具有n个元素的集合,S=⟨a1,a2,……,an⟩,现将S划分成k个满足下列条件的子集合S1,S2,……,Sk,且满足:

    1.Si≠∅

    2.Si∩Sj=∅ (1≤i,j≤k,i≠j1≤i,j≤k,i≠j)

    3.S1∪S2∪S3∪…∪Sk=S

    则称S1,S2,……,Sk是集合S的一个划分。它相当于把S集合中的n个元素a1,a2,……,an 放入k个(0<k≤n<30)无标号的盒子中,使得没有一个盒子为空。请你确定n个元素a1,a2,……,an 放入kk个无标号盒子中去的划分数S(n,k)。

    【输入】

    给出n和k。

    【输出】

    n个元素a1,a2,……,an 放入k个无标号盒子中去的划分数S(n,k)。

    【输入样例】

    10 6
    

    【输出样例】

    22827
    

    设f~i,j~为i个元素时分成j个集合的方案数。

    对任意的n,当满足k=n的时候,则f~n,k~=1。

    分析除特殊情况外的一般情况f~4,,3~=6,则是由:

    方案一:1,2;3;4

    方案二:1;2,3;4

    方案三:1;2;3,4

    方案四:1,3;2;4

    方案五:1,4;2;3

    方案六:2,4;1;3

    组成的。

    可以将其理解为f~3,3~的情况往里加了元素4。

    这样4就有两种情况,自己成为独立的集合(方案一,二,四);加入之前的集合(方案三,五,六)

    (和ybt1192放苹果类似)

    分这两类讨论:

    如果新元素自己成为集合,那么就简化成讨论剩下i-1个元素分到j-1个集合的方案

    如果新元素加入原有集合,那么就简化为讨论剩下i-1个元素分到原有j个集合的方案

    但是新元素可以加入原有j个集合中任意一个,所以要乘j。

    写出方程:f~i,j~=f~i-1,j-1~+j*f~i-1,j~

    #include<iostream>
    using namespace std;
    long long n,k,f[505][505];
    int main() {
    	cin>>n>>k;
    	for(int i=1;i<=n;i++) {
    		f[i][i]=1;
    		f[i][1]=1;
    	}
    	for(int i=2;i<=n;i++)
    		for(int j=2;j<i;j++) {
    			f[i][j]=f[i-1][j-1]+j*f[i-1][j];
    		}
    	cout<<f[n][k]<<endl;
    	return  0;
    }
    

    当然,也可以用滚动数组优化成一维数组:

    #include<iostream>
    using namespace std;
    long long n,k,f[505];
    int main() {
    	cin>>n>>k;
    	for(int i=1;i<=n;i++) {
    		f[i]=1;
    	}
    	for(int i=2;i<=n;i++)
    		for(int j=i-1;j>=2;j--) {//因为更新f[j]时要调用f[j-1],为了消除本轮数据造成的影响,需要倒着循环
    			f[j]=f[j-1]+j*f[j];
    		}
    	cout<<f[k]<<endl;
    	return  0;
    }
    
    

    (例题也好意思发博客)

  • 相关阅读:
    JVM 内部运行线程介绍
    JAVA多线程创建与退出过程
    各种 Java Thread State【转载】
    从Tomcat无法正常关闭讲讲Java线程关闭问题【转载】
    Class.forName和ClassLoader.loadClass的比较【转载】
    .NET Core、DNX、DNU、DNVM、MVC6学习资料
    Redis 资源
    Mongodb 资源
    部署Redis for Windows服务
    Mongodb副本集搭建经验
  • 原文地址:https://www.cnblogs.com/Wild-Donkey/p/12219023.html
Copyright © 2020-2023  润新知