hdoj2069 Coin Change

来源:互联网 发布:电商平台数据分析建议 编辑:程序博客网 时间:2024/06/10 19:30

依然是生成函数,但是加了一个限制条件:每种方案的硬币总数不能超过100枚


解决的办法是维护一个状态矩阵:A[i][j];[i]的意义是凑成i元,[j]的意义是用j枚硬币来凑;A[i][j]的意义是用j枚硬币凑成i元的解决方案数目

于是多项式乘法中的两项相乘就成了状态转移的过程,例如(1+a1*x+a2*x^2+a3*x^3+...)(1+x^5+...),目前凑成3元有a3种方案,则:


A[3][0] + A[3][1] + A[3][2] + A[3][3] = a3


若a3*x^3与x^5相乘,意味着引进1个5元硬币,于是:

A[8][1]增加了A[3][0]种

A[8][2]增加了A[3][1]种

A[8][3]增加了A[3][2]种

A[8][4]增加了A[3][3]种


最后只要对A[sum][i]求和即可,i属于[0, 100]。

//还是生成函数,但要求硬币总数<=100#include <cstdio>#define MAXVAL 256#define MAXCOIN 256#define COINLIMIT 100int coins[5]={1,5,10,25,50};//[i][j]表示用j个硬币凑成i元有多少种方案int CurrentAns[MAXVAL][MAXCOIN];int Temp[MAXVAL][MAXCOIN];int solutions(int sum){//初始化//也就是描述(1+x+x^2+x^3+...)这个式子,由1元硬币组成的for (int i=0; i<=sum; ++i){for (int j=0; j<MAXCOIN; ++j){CurrentAns[i][j]=0;if(i==j) CurrentAns[i][j]=1;//这个矩阵的对角线元素一定都是1,凑m元用m个硬币,显然只有1种方案;且矩阵在对角线以下才有元素。}}//开始多项式乘法for (int i=1; i<5; ++i)//遍历5,10,25,50四种规格的硬币{//先把当前的状态表暂存下来for (int j=0; j<=sum; ++j){for (int k=0; k<MAXCOIN; ++k){Temp[j][k]=CurrentAns[j][k];}}int CurVal=coins[i];for (int j=1; j*CurVal<=sum; ++j)//当前参与乘法的项。新增j个硬币,j>=1。{for (int k=0; k+j*CurVal<=sum; ++k)//遍历乘号左边的式子的每一项,但并不是乘号左边多项式的所有项都需要和当前参与乘法的项相乘{/******************乘法前的状态:k元,分别可用0,1,2,...,k枚硬币凑出,即[k][0], [k][1], [k][2], ..., [k][k]乘法后的状态:k+j*CurVal元,分别可用0+j,1+j,2+j,...,k+j枚硬币凑。状态转移。******************/for (int l=0; /*l+j<=COINLIMIT*/l<=k; ++l)//这个式子,循环条件l<=k就不对,l+j<=100就对了,何解?因为数组的列数只有110,最初开辟的时候,越界了!哈!把数组开大,列数和行数相等,现在l<=k是对的,证实了我之前的猜测,这里根本不用限制硬币总数。{CurrentAns[k+j*CurVal][l+j]+=Temp[k][l];}}}}//在最后得到的表中统计sum元,且总硬币数小于100的solution总共有多少个int cnt=0;for (int i=0; i<=COINLIMIT; ++i){cnt+=CurrentAns[sum][i];}return cnt;}int main(){int n;while (scanf("%d", &n)!=EOF){printf("%d\n", solutions(n));}return 0;}

0 0
原创粉丝点击