2.12 二项式系数加法解 C实现

该问题出自《C语言名题精选百则技巧篇》

题目:编写一个程序,只用加法,求出n中取r个的组合系数C(n,r),并且尽可能的使加法数目降低。

我们先来了解一下二项式系数的性质:

(1) C(m,n) = C(n,n-m)

(2) C(n,r) = C(n-1,r)+C(n-1,r-1)

(3) C(n,0) = 1,C(n,1) = n, C(n,n) = 1

第一种方法:递归函数

int cnr(int n,int r)
{
    if(n==r || r ==0)
        return 1;
    else 
        return cnr(n-1,r)+cnr(n-1,r-1);
}
我们来分析一下,上面这种方法用到的加法的个数。

用A(n,r)表示在计算C(n,r)时所用到的加法的个数,从if部分看,当n=r以及r=0时没有用到加法,因此A(n,n) = A(n,0) = 0;从else的部分看,要先计算C(n-1,r)和C(n-1,r-1), 一共用了A(n-1,r)和A(n-1,r-1)个加法,最后又多了一个加法,因此A(n,r)可以表示为:

        A(n,r) = 0      n==r或者r==0

        A(n,r) = A(n-1,r)+A(n-1,r-1)+1.

由二项式性质的(2)和(3)很容易想到A(n,r) = C(n,r) -1 = n(n-1)...(n-r+1)/[r(r-1)...*3*2*1]-1.与n^r成正比。

第二种方法:杨辉三角(Pascal)

            n=0         1

         n=1        1      1
    n=2         1      2      2

n=3         1      3      3       1

杨辉三角程序

int cnr(int n,int r)
{
    int answer[MAXSIZE];
    int i,j;
    
    answer[0] =1;
    for(i=1;i<=n;i++)
         for(answer[i]=1,j=i-1;j>=1;j--)
              answer[j]+=answer[j-1];
     return answer[r];
}
i = 2时1个加法,i=3时2个加法,i=n时n-1个加法。总共n(n-1)/2个加法。

第三种方法,根据杨辉三角演变出来的

根据杨辉三角演变出来的,但是不按三角形形状顺序进行加法的计算。

C(0,0)    C(1,1)   C(2,1)     C(3,3)

C(1,0)    C(2,1)    C(3,2)     C(4,3)

C(2,0)    C(3,1)    C(4,2)     C(5,3)

C(3,0)    C(4,1)    C(5,2)     C(6,3)

C(4,0)    C(5,1)    C(6,2)     C(7,3)

C(5,0)     C(6,1)   C(7,2)      C(8,3)

先把所有元素都初始化为1,从C(2,1)开始,每一个元素等于它的左边的元素和上边的元素的值相加。所以一共只需要加15次就可以得到结果C(8,3). 可以先计算行也可以先计算列,我们下边按行的顺序相加。

ijc[j]对应
 1 c[1] = c[1] +c[0] =2C(2,1)
1 2c[2] = c[2] +c[1] =3C(3,2)
1 3c[3] = c[3] +c[2] = 4C(4,3)
2 1c[1] = c[1] +c[0] = 3C(3,1)
2 2c[2] = c[2] +c[1] =6 C(4,2)
2 3c[3] = c[3] +c[2] =10C(5,3)
3 1c[1] = c[1] +c[0] = 4C(4,1)
3 2c[2] = c[2] + c[1] = 10 C(5,2)
33c[3] = c[3] + c[2] = 20C(6,3)
41c[1] = c[1] +c[0] = 5 C(5,1)
42c[2] = c[2] + c[1] = 15C(6,2)
43c[3] = c[3] +c[2] = 35C(7,3)
51c[1] = c[1] + c[0] = 6C(6,1)
52c[2] = c[2] + c[1] =21C(7,2)
 5   3    c[3] = c[3] + c[2] = 56     C(8,3)
代码如下:

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
unsigned long cnr(int n,int r)
{
	unsigned long c[MAXSIZE];
	int i,j;
	for(i=0;i<=r;i++)
	    c[i] = 1UL;
	for(i=1;i<=n-r;i++)
	    for(j=1;j<=r;j++)
	        c[j]+=c[j-1];
	return c[r];
}
int main(int argc,char *argv[])
{
	int n,r;
	unsigned long answer;
	printf("\nCnr  Program:m^n");
	printf("\nInput n -->");
	scanf("%d",&n);
	printf("\nInput r -->");
	scanf("%d",&r);
	answer = cnr(n,r);
    
    printf("The answer of Cnr is:Cnr = %ld",answer);
    
	
	while(1)
	    getchar();
	return 0;
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 QML 的 ListView 组件来实现两列多行的表单。ListView 组件提供了一个可滚动的列表视图,可以根据数据模型动态生成多个列表项。 以下是一个简单的示例,展示如何使用 ListView 组件创建两列多行的表单: ``` ListModel { id: formData ListElement { name: "Name"; value: "" } ListElement { name: "Age"; value: "" } ListElement { name: "Address"; value: "" } ListElement { name: "Phone"; value: "" } } ListView { id: formList anchors.fill: parent model: formData delegate: Row { spacing: 10 Text { text: model.name } TextField { text: model.value } } // 设置两列布局 clip: true orientation: ListView.Vertical property int columns: 2 property int rows: Math.ceil(formList.count / columns) height: rows * (delegate.height + spacing) - spacing width: columns * delegate.width + (columns - 1) * spacing } ``` 在上面的示例中,我们定义了一个名为 formData 的 ListModel,其中包含了四个列表元素,每个元素都有一个名字和一个值。然后,我们使用 ListView 组件将 formData 作为数据模型,并在 delegate 属性中定义了一个 Row 组件来表示每个列表项。每个 Row 组件包含一个 Text 组件用于显示列表元素的名称,以及一个 TextField 组件用于输入列表元素的值。最后,我们设置 clip、orientation、columns 和 rows 属性来指定两列多行的布局,并根据行数和列数计算出列表视图的宽度和高度。 你可以根据需要调整列表项的样式和布局,以及使用不同的数据模型来自定义表单的外观和行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值