首页 新闻 搜索 专区 学院

一个看似简单,然而并不容易的高中排列组合题

0
悬赏园豆:10 [已解决问题] 解决于 2019-03-13 10:12

有一个n位数递增的数列,每位上的数最小可以为1,最大为m,问总共有多少种情况,写出一个通用的公式。

比如n=2,m=3时有6种情况

[1 1]
[1 2]
[1 3]
[2 2]
[2 3]
[3 3]

n=3,m=4时有20种情况

[1 1 1]
[1 1 2]
[1 1 3]
[1 1 4]
[1 2 2]
[1 2 3]
[1 2 4]
[1 3 3]
[1 3 4]
[1 4 4]
[2 2 2]
[2 2 3]
[2 2 4]
[2 3 3]
[2 3 4]
[2 4 4]
[3 3 3]
[3 3 4]
[3 4 4]
[4 4 4]
Xiangism的主页 Xiangism | 初学一级 | 园豆:80
提问于:2019-03-07 11:07
< >
分享
最佳答案
0

C(n+m-1,n)
设a[i]表示数字i出现的次数,那么a[1]+a[2]+..+a[m]=n,其中所有a[i]都是自然数
可以发现,一组这个方程的解恰好对应一个题目所求情况,因此题目所求方案数等于这个方程的解数
这个方程的解数量,直接用隔板法就可以求

收获园豆:4
hehe_54321 | 小虾三级 |园豆:750 | 2019-03-07 17:21

C(n+m-1,n) 是正解。
但方程的解数是如何对应题目所求情况呢?

Xiangism | 园豆:80 (初学一级) | 2019-03-08 15:39

@Xiangism:
a[i]表示序列中数字i出现的次数,a[1]+a[2]+..+a[m]=n,
那么m表示可以出现的数字有1,2,..,m,n就表示各个数字出现的总次数(也就是序列长度)
比如n=9,m=3,a[1]=2,a[2]=3,a[3]=4
对应的序列就是[1,1,2,2,2,3,3,3,3]

其实吧,这个“...恰好对应...”只是为了表述方便,只是想说明这个方程的一个解是一个合法序列的另一种表示方法,要更严格我就说不清楚了。。。

hehe_54321 | 园豆:750 (小虾三级) | 2019-03-10 19:13
其他回答(2)
0

实际上用程序来实现也很简单


#include <stdio.h>

int a[10005];
int n,m;
void fun(int x,int value)
{
    if(x==n)
    {
        for(int i=0;i<n;i++)
        {
            printf("%d ",a[i]);
        }
        printf("\n");
        return;
    }
    
    for(int i=value==0?1:value;i<=m;i++)
    {
        a[x] = i;
        fun(x+1,i);
    }
}

int main()
{

    scanf("%d%d",&n,&m);
    
    fun(0,0);

}
收获园豆:4
Shendu.CC | 园豆:1914 (小虾三级) | 2019-03-07 11:48

不错。我是用非递归的方式实现的

type ListFactory struct {
    // 总共有的元素个数
    Count int

    // 每个元素最大可取的数
    Max int

    now []int
}

func NewList(count, max int) *ListFactory {
     r := ListFactory{
        Count:count,
        Max:max, }

    r.now = make([]int, count)

    r.Init(1)

    return &r
}

func (n *ListFactory) Init(c int ) {
    for i := 0; i < n.Count-1; i += 1 {
        n.now[i] = c
    }
    n.now[n.Count-1] = c-1
}

func (n *ListFactory) incr() bool {

    if n.now[n.Count-1] < n.Max {
        n.now[n.Count-1] += 1
        return true
    }

    i := n.Count-1
    for ; i >= 0; i -= 1 {
        if n.now[i] != n.Max {
            break
        }
    }
    if i < 0 {
        return false
    }
    if i == 0  && n.now[0] == n.Max{
        return false
    }

    n.now[i] += 1
    v := n.now[i]

    for j := i+1; j < n.Count; j += 1 {
        n.now[j] = v
    }

    return true
}

func (n *ListFactory) Create() (bool, []int) {
    if n.incr() {
        return true, n.now
    } else {
        return false, nil
    }
}
支持(0) 反对(0) Xiangism | 园豆:80 (初学一级) | 2019-03-07 13:49

@Xiangism: 这是什么语言?

支持(0) 反对(0) Shendu.CC | 园豆:1914 (小虾三级) | 2019-03-07 14:43

@Shendu.CC: go语言

支持(0) 反对(0) Xiangism | 园豆:80 (初学一级) | 2019-03-07 16:14
0

插空法吧,总共m个空,插n个数据,但可以多个数插到一个空里,对于多个数据插一个空里用隔板法,每种插法就是一种可能的序列
所以:
插到一个空里:c(1,m)xc(0,n-1)
插到两个空里:c(2,m)xc(1,n-1)
插到三个空里:c(3,m)xc(2,n-1)
插到四个空里:c(4,m)xc(3,n-1)
。。。
插到n个空里:c(n,m)xc(n-1,n-1)
结果是上加的结果相加
n=2,m=3时:3x1+3x1=6
n=3,m=4时:4x1+6x2+4x1=20
可以想一下怎么化简,化简的结果可能就是另一种好的解法的解
手动解不好解,但用程序还是很好解的

收获园豆:2
流年飞雨 | 园豆:1983 (小虾三级) | 2019-03-08 15:38

C(n+m-1,n) 是化简后的结果。

这个问题有一个通用的名字: “重复组合”问题

支持(0) 反对(0) Xiangism | 园豆:80 (初学一级) | 2019-03-08 15:44
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册