POJ1306 组合数学之排列 基础例子(一)

来源:互联网 发布:顺昌一中网络平台 编辑:程序博客网 时间:2024/05/19 18:00

题目

GIVEN: 5 <= N <= 100; 5 <= M <= 100; M <= N
Compute the EXACT value of: C = N! / (N-M)!M!

题目大意:就是n中拿m个,有几种情况

思路:鉴于100!=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

所以要婉转些来。但是用大数处理有很繁琐。Orz!但是,注意到因为分母一定可以约掉分子,所以肯定可以在分子归拢相乘的同时可以先约到最简的模式再相乘!所以可以先找出和分子每一个乘数的最大公约数,上下分子分母约掉!

 

program1:(模拟)

#include<iostream>
using namespace std;
int m,n;
int low,high;
int a[105];
int gcd(int a,int b)
{
  if(a%b==0)return b;
  else return gcd(b,a%b);    //一开始竟然忘了return,我嚓~~
}
int main()
{
while(scanf("%d%d",&n,&m)&&(n||m))
{
if(m>n-m)              //直接模拟排列的运算过程
{
  low=m+1;
  high=n-m;        
}          
else
{
   low=n-m+1;
   high=m;   
}
//printf("low high %d %d \n",low,high);
for(int i=1;i<=high;i++)
      a[i]=i;
int k,tmp;
__int64 sum=1;
for(int i=low;i<=n;i++)
{
    k=i;
   for(int j=2;j<=high;j++)
   {
      tmp=gcd(k,a[j]);                //找出最大公约数来约分
      if(tmp!=1)
        {
            k/=tmp;
            a[j]/=tmp;// 一开始竟然忘了约掉分母,再嚓~~
        }  
   }
   sum*=k;     
}
//printf("%lld\n",sum);
printf("%d things taken %d at a time is %I64d exactly.\n",n,m,sum);                   
}
//system("pause");
return 0;}

 

program2(DP):

简单DP                C(N,M)=C(N-1,M-1)+C(N-1,M);

#include<iostream>
using namespace std;
__int64 mm[102][102];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF ,n||m )
{
  memset(mm,0,sizeof(mm));
  for(int i=0;i<=n;i++)
     mm[i][0]=1;
  for(int i=1;i<=n;i++)///
     mm[i][i]=1;
  for(int i=1;i<=n;i++)
     for(int k=1;k<i;k++)///注意k不是1,竟然有数组越界不RE而是WA
        {
          mm[i][k]=mm[i-1][k-1]+mm[i-1][k];
          if(n==i&&m==k)
             break;
        }
  printf("%d things taken %d at a time is %I64d exactly.\n",n,m,mm[n][m]);
  //printf("%I64d\n",mm[n][m]);         
}
system("pause");
return 0;}