【POJ - 1942 】Paths on a Grid (组合数学,求组合数的无数种方法)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/83862772

题干:

Imagine you are attending your math lesson at school. Once again, you are bored because your teacher tells things that you already mastered years ago (this time he's explaining that (a+b) 2=a 2+2ab+b 2). So you decide to waste your time with drawing modern art instead. 

Fortunately you have a piece of squared paper and you choose a rectangle of size n*m on the paper. Let's call this rectangle together with the lines it contains a grid. Starting at the lower left corner of the grid, you move your pencil to the upper right corner, taking care that it stays on the lines and moves only to the right or up. The result is shown on the left: 


Really a masterpiece, isn't it? Repeating the procedure one more time, you arrive with the picture shown on the right. Now you wonder: how many different works of art can you produce?

Input

The input contains several testcases. Each is specified by two unsigned 32-bit integers n and m, denoting the size of the rectangle. As you can observe, the number of lines of the corresponding grid is one more in each dimension. Input is terminated by n=m=0.

Output

For each test case output on a line the number of different art works that can be generated using the procedure described above. That is, how many paths are there on a grid where each step of the path consists of moving one unit to the right or one unit up? You may safely assume that this number fits into a 32-bit unsigned integer.

Sample Input

5 4
1 1
0 0

Sample Output

126
2

题目大意:

扫描二维码关注公众号,回复: 4011310 查看本文章

一个n行m列的矩阵,让你从左下角走到右上角,每次只能向上或者向右走,问你有多少种方法数。

解题报告:

  一道高中数学题啊,,,一共肯定走n+m步,我们挑n步向上走,剩下m步都向右走就可以了。所以其实就是求C(n+m,n)或者C(n+m,m)。他说范围不会超Unsigned int。我们这里用longlong去存。刚开始想着打表,,因为C(20,10)这样的数就很大了,,肯定不会超1000吧。。。然后就RE了,,一想发现确实是这样,因为我也可以C(100000,1),这样的数也是不超int范围的,,但是你打表就打不出来了。。

考虑用公式C(n,m)公式写出来发现不能用啊,因为阶乘这东西可不是闹着玩的,,,10的阶乘就300W(3e6)了。。所以我们只能提前除掉其中一部分。。

其实这题如果加个取模就好做了。。。一万种方法可以求。。(甚至可以Lucas)但是这题不能用。

所以这题两个解法,一个是用double暴力,最后四舍五入得到答案。

另一个是直接用longlong去约分,因为会发现有中间项可以约分并且一定可以整除。

此时发现中间项可以分母分子约掉,,所以是可以整除的不会有精度损失。 

RE代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;

ll C[1005][1005];
int main()
{
	C[0][0] = 1;
	for(int i = 1; i<=1002; i++) {
		C[i][0] = 1;
		for(int j = 1; j<=1002; j++) {
			C[i][j] = C[i-1][j] + C[i-1][j-1];
		}
	}
	int n,m;
	while(~scanf("%d%d",&n,&m)) {
		if(n+m==0) break;
		printf("%lld\n",C[n+m][n]);
	}
	return 0 ;
 }

TLE代码:(感觉TLE的原因就是因为没有去取m和n中的较小值)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;

//ll C[2005][2005];
ll c(ll n,ll m) {
	ll x = n-m;
	ll all = x;
	double res = 1;
	for(ll i = 1; i<=all; i++) {
		res *= (1.0*n)/x;
		x--,n--;
	}
	return round(res);
}
int main()
{
//	C[0][0] = 1;
//	for(int i = 1; i<=1000; i++) {
//		C[i][0] = 1;
//		for(int j = 1; j<=1000; j++) {
//			C[i][j] = C[i-1][j] + C[i-1][j-1];
//		}
//	}
	ll n,m;
	while(~scanf("%lld%lld",&n,&m)) {
		if(n+m==0) break;
		printf("%lld\n",c(n+m,min(n,m)));
	}
	return 0 ;
 }

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;

//ll C[2005][2005];
ll c(ll n,ll m) {//c(5,2)
	ll cha1 = n-m;
	ll cha2 = m;
	ll cha = min(cha1,cha2);
	ll j = n-cha+1;
	ll i = 1;
	ll res = 1;
	for(;i<=cha;i++,j++) {
		res = res*j/i;
	}
	return res;
}
int main()
{
//	C[0][0] = 1;
//	for(int i = 1; i<=1000; i++) {
//		C[i][0] = 1;
//		for(int j = 1; j<=1000; j++) {
//			C[i][j] = C[i-1][j] + C[i-1][j-1];
//		}
//	}
	ll n,m;
	while(~scanf("%lld%lld",&n,&m)) {
		if(n+m==0) break;
		printf("%lld\n",c(n+m,min(n,m)));
	}
	return 0 ;
 }

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/83862772
今日推荐