首页 > 代码库 > AOJ 169 找零钱 DP OR 母函数

AOJ 169 找零钱 DP OR 母函数

一直觉得这题因为有总量限制,是不能用母函数解的,今天偶然发现原来是可以的,记录一下。

只要搞母函数的时候多开一维来表示用了多少个硬币就好了,其实就是目标状态是二维的母函数

类似于 假设我现在要处理的面值是2      (1 + x^2 * y + x^4 * y ^ 2 + x ^ 6 * y ^ 3...) 就表示用0个,1个,2个,3个..硬币的状态了。

看来母函数最重要的还是对式子本身的理解,这样才能应对各种变化。

#include <cstdio>#include <cstring>#include <iostream>#include <map>#include <set>#include <vector>#include <string>#include <queue>#include <deque>#include <bitset>#include <list>#include <cstdlib>#include <climits>#include <cmath>#include <ctime>#include <algorithm>#include <stack>#include <sstream>#include <numeric>#include <fstream>#include <functional>using namespace std;#define MP make_pair#define PB push_backtypedef long long LL;typedef unsigned long long ULL;typedef vector<int> VI;typedef pair<int,int> pii;const int INF = INT_MAX / 3;const double eps = 1e-8;const LL LINF = 1e17;const double DINF = 1e60;const int maxk = 7;const int maxc = 105;const int maxn = 255;const int Coins[] = {1, 2, 5, 10, 20, 50, 100};int C1[maxn][maxc], C2[maxn][maxc];int f[maxn];void init() {    C1[0][0] = 1;    //用哪种硬币    for(int i = 0; i < maxk; i++) {        //用几个        for(int j = 0; j * Coins[i] <= 250; j++) {            //枚举从哪里更新            for(int k = 0; k + j * Coins[i] <= 250; k++) {                //附加一层循环控制总量                for(int l = 0; l + j <= 100; l++) {                    C2[k + j * Coins[i]][l + j] += C1[k][l];                }            }        }        memcpy(C1,C2,sizeof C1);        memset(C2,0,sizeof C2);    }    //累加每种硬币总数的情况    for(int i = 0;i <= 250;i++) {        for(int j = 0;j <= 100;j++) f[i] += C1[i][j];    }}int main() {    init();    int n;    while(scanf("%d", &n), n) printf("%d\n",f[n]);    return 0;}

  

 

当然因为这里没有硬币的上下数量限制,用DP搞很轻松随意

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <climits>#include <string>#include <iostream>#include <map>#include <cstdlib>#include <list>#include <set>#include <queue>#include <stack> using namespace std; typedef long long LL; int N,C[7] = {1,2,5,10,20,50,100};int f[100][7][250];int dfs(int now,int prev,int sum) {    if(sum == 0) return 1;    if(sum < 0) return 0;    if(now == 100) return 0;    int ret = 0,&note = f[now][prev][sum];    if(note != -1) return note;    for(int i = prev;i < 7;i++) {        ret += dfs(now + 1,i,sum - C[i]);    }    return note = ret;} int main() {    memset(f,-1,sizeof(f));    while(cin >> N,N) {        cout << dfs(0,0,N) << endl;    }    return 0;}