ybt1315 递归例题(虽然没用递归)集合划分

ybt1315 集合划分

递归算法

【题目描述】

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

1.Si≠∅Si≠∅

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

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

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

【输入】

给出nn和kk。

【输出】

nn个元素a1,a2,……,ana1,a2,……,an 放入kk个无标号盒子中去的划分数S(n,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;
}

(例题也好意思发博客)

猜你喜欢

转载自www.cnblogs.com/Wild-Donkey/p/12219023.html
今日推荐