poj 1285简单的组合

来源:互联网 发布:图书购买系统c语言 编辑:程序博客网 时间:2024/05/17 03:08

这道题第一遍看觉得是有公式的,但是用动态规划更加简单啦!简单说一下我的思路:

首先将输入的数组进行排序

建立一个数组b[i][j]表示从第i个元素开始(包括i)中抽取j个数的不同的种类数

则b[i][j]=b[i+1][j-1]+b[x][j]

b[i+1][j-1]:代表将第i个数取出,那么剩下的就是求从i+1个元素开始种去j-1个数的不同种类数

b[x][j]:代表第i个数没有取,因为数组中有数重复,而且数组又是排过序的,则x代表的是从第i个元素之后不等于第i个元素的第一个数,

本题的大致思路就是这个,这个思路也是从别人那里借鉴了一下,以后得提高自己分析问题的能力啊!

超时的代码:这个代码是我用纯粹的递归写的,然后针对每个输入的r都递归一次,结果超时了,所以以后要总结经验,有的时候有更好的方法就不能使用递归的!

#include<iostream>#include<algorithm>using namespace std;int a[55],n,m;int cmp(const void *a,const void *b){return *(int *)a-*(int *)b;}unsigned __int64 fun(int m, int r){if(m>n)return 0;if(r==0)return 1; int i;i=m;while(a[i]==a[m])//找到和那个和a[m]不相同的第一个值得i++;if(i<=n)return fun(m+1,r-1)+fun(i,r);elsereturn fun(m+1,r-1);}int main(){    int i,j,r,k=0;while(1){//cin>>n>>m;scanf("%d%d",&n,&m);if(n==0)break;for(i=0; i<n; i++)scanf("%d",&a[i]);qsort(a,n,sizeof(int),cmp);k++;printf("Case %d:\n",k);for(j=0;j<m; j++){scanf("%d",&r);unsigned __int64 m=fun(0,r);printf("%I64d\n",m);}}return 0;}

改进的算法:将所算的的结果存储在二维数组中,对于一组输入数据,先找出需要求的最大的组合数,针对它进行求解,则比它小的数就可以直接从二维数组里面取得结果啦!

代码如下(这个代码的效率相当高啦!哈哈):

#include<iostream>#include<algorithm>using namespace std;int a[55],n,m;unsigned __int64 b[55][55];int cmp(const void *a,const void *b){return *(int *)a-*(int *)b;}unsigned __int64 fun(int m, int r){if(m>=n)return 0; int i;i=m;while(a[i]==a[m])//找到和那个和a[m]不相同的第一个值得i++;if(i<=n)b[m][r]=b[m+1][r-1]+fun(i,r);//return fun(m+1,r-1)+fun(i,r);elseb[m][r]=b[m+1][r-1];//return fun(m+1,r-1);return b[m][r];}int main(){    int i,j,r,k=0;    int c[55];while(1){//cin>>n>>m;scanf("%d%d",&n,&m);if(n==0)break;for(i=0; i<n; i++)scanf("%d",&a[i]);qsort(a,n,sizeof(int),cmp);k++;for(i=0; i<=n; i++){b[i][0]=1; for(j=1; j<=n; j++)b[i][j]=0;}printf("Case %d:\n",k);int ma=0;for(j=0;j<m; j++){scanf("%d",&c[j]);if(c[j]>ma)ma=c[j]; }for(i=1; i<=ma; i++)for(j=0; j<n; j++)       fun(j,i);//取最大的进行求值的for(j=0; j<m; j++)printf("%I64d\n",b[0][c[j]]);}return 0;}