poj 1942 Paths on a Grid (求组合数)

题目链接

POJ1942

题目大意

在一个尺寸为N*M的网格中(N,M均为无符号32位整数),求从网格左下角走到网格右上角有几种走法,如下图为两种符合要求的走法:
这里写图片描述

分析

看到这道题会想用递推去做,但这里n与m都很大,用递推无论是时间复杂度还是空间复杂度都不能实现。
再仔细思考,不难发现,每一种方案中,都是n步向上走,m步向右走,即总步数确定,不一样的只是’右’和’上’出现的相对顺序。那么这个问题就相当于在n+m个位置中我取n个位置来放’上’这张卡片的方案数,即求 Cnn+m Cmn+m
接着就是要解决如何求组合数的问题,由于这里n,m很大,不能再用杨辉三角的递推关系去求,而要利用组合数的阶乘公式:

Cmn=n!m!(nm)!

下面总结用一种计算组合数的高效方法:
其实就是用我们平时笔算组合数 Cmn 的简便方法: 将n!与(n-m)!中的公因子进行约分,可以发现分子为n向下逐一递减的m项,分母为m!(也为m项),这样便能将时间复杂度控制在O(n-m)。这里涉及除法运算,因此用double储存数据,那么最后要转化为 无符号整型 时就要处理精度问题,有两种方法: 四舍五入+强制类型转换 或者用 setprecision()函数 。

代码

若用setprecison()函数处理精度

#include <iostream>
#include <cmath>
#include <iomanip>  //setprecision()必要头文件
using namespace std;
double comp(unsigned int n,unsigned int m)//求nCm
{
    m=min(m,n-m); //计算优化:将上标化小
    double ans=1.0;
    while (m>0)
        ans*=double(n--)/double(m--);
    return ans;
}
int main()
{
    unsigned int n,m;
    while (cin>>n>>m)
    {
        if (!n&&!m) break;
        cout<<fixed<<setprecision(0)<<comp(n+m,m)<<endl;//记住这句话格式,用该函数会自动四舍五入保留相应位数
    }
    return 0;
}

若用四舍五入+强制类型转换
对应计算组合数的函数如下

unsigned int comp(unsigned int n,unsigned int m)//求nCm
{
    m=min(m,n-m); 
    double ans=1.0;
    while (m>0)
        ans*=double(n--)/double(m--);
    ans+=0.5;//double转unsigned会强制截断小数,必须先四舍五入
    return (unsigned)ans;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值