vb组合数c(n,m) 递归求法,要用function函数。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vb组合数c(n,m) 递归求法,要用function函数。相关的知识,希望对你有一定的参考价值。

对于c(n,m)有如下递归公式:c(n,m)=c(n,m-1)=c(n-1,m-1)

递归条件: 当n=0,c(0.m)=1
当n=1,c(1.m)=m
当n>m/2, c(n,m)=c(m-n,m)

参考技术A  Function c(ByVal n, ByVal m)
   If n > m / 2 Then n = m - n
   If n = 0 Then
      c = 1
   ElseIf n = 1 Then
      c = m
   Else
      c = c(n, m - 1) + c(n - 1, m - 1)
   End If
End Function

Private Sub Command1_Click()
   Dim n As Integer, m As Integer
   n = Val(InputBox("n=?"))
   m = Val(InputBox("m=?"))
   If m >= n And n >= 1 Then
      MsgBox "c(" & n & "," & m & ")=" & c(n, m)
   Else
      MsgBox "输入的数不符合条件!"
   End If
End Sub

追问

当n>m/2, c(n,m)=c(m-n,m),这个条件是没有用的吗??

追答Function c(ByVal n, ByVal m)
   If n > m / 2 Then n = m - n'这一句不是用了吗?
   If n = 0 Then
      c = 1
   ElseIf n = 1 Then
      c = m
   Else
      c = c(n, m - 1) + c(n - 1, m - 1)
   End If
End Function
 
 '下面的代码更直观的运用了三个条件
Function c(ByVal n, ByVal m)
   If n = 0 Then
      c = 1
   ElseIf n = 1 Then
      c = m
   ElseIf n > m / 2 Then
      c = c(m - n, m)
   Else
      c = c(n, m - 1) + c(n - 1, m - 1)
   End If
End Function
Private Sub Command1_Click()
   Dim n As Integer, m As Integer
   n = Val(InputBox("n=?"))
   m = Val(InputBox("m=?"))
   If m >= n And n >= 1 Then
      MsgBox "c(" & n & "," & m & ")=" & c(n, m)
   Else
      MsgBox "输入的数不符合条件!"
   End If
End Sub

组合数

从n个元素里取出m个,记C(n,m); 原始公式:C(n,m) = n! / ( m!*(n-m)! )

在编程里,初中高中的阶乘公式已经不太管用了,数据一下子就爆。

 

公式1:C(n,m) = (n-m+1) * C(n,m-1) / m

用数组存放,从C(n,0)开始存到C(n,m),数组下标表示m的值

且看题目:(裸题)

Binomial Showdown

In how many ways can you choose k elements out of n elements, not taking order into account? 

Write a program to compute this number.

Input

The input will contain one or more test cases. 
Each test case consists of one line containing two integers n (n>=1) and k (0<=k<=n). 
Input is terminated by two zeroes for n and k.

Output

For each test case, print one line containing the required number. This number will always fit into an integer, i.e. it will be less than 2 31
Warning: Don‘t underestimate the problem. The result will fit into an integer - but if all intermediate results arising during the computation will also fit into an integer depends on your algorithm. The test cases will go to the limit. 

Sample Input

4 2
10 5
49 6
0 0

Sample Output

6
252
13983816
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
long long a[9999999];

int main()///裸题,单纯套公式
{
    long long n,k,i;
    while(cin>>n>>k&&(n+k))
    {
        a[0]=1;
        if(k>n-k)
            k=n-k;
        for(i=1;i<=k;i++)
            a[i]=(n-i+1)*a[i-1]/i;
        cout<<a[k]<<endl;
    }
    return 0;
}

 

公式2:C(n,m) = C(n-1,m) + C(n-1,m-1)

计算较大的组合数,用二维数组存放各个组合数的大小

且看裸题:

O - Combinations

Computing the exact number of ways that N things can be taken M at a time can be a great challenge when N and/or M become very large. Challenges are the stuff of contests. Therefore, you are to make just such a computation given the following:

GIVEN: 5 <= N <= 100; 5 <= M <= 100; M <= N 
Compute the EXACT value of: C = N! / (N-M)!M! 
You may assume that the final value of C will fit in a 32-bit Pascal LongInt or a C long. For the record, the exact value of 100! is: 
93,326,215,443,944,152,681,699,238,856,266,700,490,715,968,264,381,621, 468,592,963,895,217,599,993,229,915,608,941,463,976,156,518,286,253, 697,920,827,223,758,251,185,210,916,864,000,000,000,000,000,000,000,000 

Input

The input to this program will be one or more lines each containing zero or more leading spaces, a value for N, one or more spaces, and a value for M. The last line of the input file will contain a dummy N, M pair with both values equal to zero. Your program should terminate when this line is read.

Output

The output from this program should be in the form: 
N things taken M at a time is C exactly. 

Sample Input

100  6
20  5
18  6
0  0

Sample Output

100 things taken 6 at a time is 1192052400 exactly.
20 things taken 5 at a time is 15504 exactly.
18 things taken 6 at a time is 18564 exactly.

代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;

long long c[101][101];

int main()
{
    for(int i=1;i<101;i++)
    {
        c[i][0]=c[0][i]=1;
        c[i][i]=1;          //不用担心下面n和k相等没法进入循环的情况
    }
    for(int n=1;n<101;n++)
        for(int k=1;k<n;k++)//一直是k<=n;不过等于的情况解决了
        c[n][k]=c[n-1][k]+c[n-1][k-1];
    int n,k;
    while(cin>>n>>k&&(n+k))
    {
        printf("%d things taken %d at a time is %d exactly.
",n,k,c[n][k]);
    }
    return 0;
}

 

数据更大,需要求模,一般用鲁卡斯定理:
C(n,m)%p p为素数,总有:
m = t*p + r
n = s*p + q → C(n,m)%p = C(s,t)%p * C(q,r)%p → C(n,m)%p = C(n/p,m/p)%p * C(m%p,n%p)%p

题目:

Saving Beans

 
Although winter is far away, squirrels have to work day and night to save beans. They need plenty of food to get through those long cold days. After some time the squirrel family thinks that they have to solve a problem. They suppose that they will save beans in n different trees. However, since the food is not sufficient nowadays, they will get no more than m beans. They want to know that how many ways there are to save no more than m beans (they are the same) in n trees. 

Now they turn to you for help, you should give them the answer. The result may be extremely huge; you should output the result modulo p, because squirrels can’t recognize large numbers.

InputThe first line contains one integer T, means the number of cases. 

Then followed T lines, each line contains three integers n, m, p, means that squirrels will save no more than m same
beans in n different trees, 1 <= n, m <= 1000000000, 1 < p < 100000 and p is guaranteed to be a prime.OutputYou
should output the answer modulo p.
Sample Input

2
1 2 5
2 1 5
Sample Output
3
3 
Hint

For sample 1, squirrels will put no more than 2 beans in one tree. Since trees are different, we can label them as 1, 2 … and so on. 
The 3 ways are: put no beans, put 1 bean in tree 1 and put 2 beans in tree 1. For sample 2, the 3 ways are:
 put no beans, put 1 bean in tree 1 and put 1 bean in tree 2.


思路:由于树上可以不放豆,C(n+m,m)。数据太大,需要很多防爆措施,快速幂,逆元,阶乘,鲁卡斯定理。
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#define ll long long
using namespace std;

ll n, m, p;
ll fac[1000000+10]={1,1};   ///0和1的阶乘为1

void getfac()               ///打印阶乘表
{
    for(ll i=1;i<=p;i++)    ///每次打到p就好
        fac[i]=fac[i-1]*i%p;
}

ll power(ll a,ll b,ll p)    ///大数据逆元计算又需要快速幂
{   ///a的b次方对p求模
    ll ans=1;
    while(b>0)
    {
        if(b%2==1)
            ans=ans*a%p;
        b>>=1;
        a=a*a%p;
    }
    return ans%p;
}


ll C(ll n, ll m ,ll p)
{   ///C(n,m) = n! / ( m!*(n-m)! )
    ///数据太大肯定爆,p又是素数。换成求m!*(n-m)!的逆元,又不能一起求,会爆数据,分开求,看做n!/m! * 1/(n-m)!
    ///由于是对p求模,n,m范围在阶乘表范围里
    if(m>n)
        return 0;
    return fac[n]%p * power(fac[m], p-2, p) * power(fac[n-m], p-2, p) % p;
}

ll lucase(ll n, ll m )
{
    if(m==0)
        return 1;
    else
        return C(n%p, m%p, p)* lucase(n/p,m/p)%p;/// (n/p),(m/p)不一定比p小,继续用鲁卡斯
}


int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>p;
        getfac();
        cout<<lucase(n+m,n)<<endl;
    }
    return 0;
}

 

 





























以上是关于vb组合数c(n,m) 递归求法,要用function函数。的主要内容,如果未能解决你的问题,请参考以下文章

Lucas组合数定理组合-FZU 2020

wenbao与组合数

02方法-作业01-递归练习

数论篇7——组合数 & 卢卡斯定理(Lucas)

组合数—学习笔记

变态组合数求解方法