• 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_back
    typedef 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
    ",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;
    }
    

      

  • 相关阅读:
    bzoj1904: Musical Water-fence
    bzoj3822: 文学
    bzoj1513: [POI2006]Tet-Tetris 3D
    bzoj4130: [PA2011]Kangaroos
    bzoj2515 Room
    bzoj2518: [Shoi2010]滚动的正四面体
    bzoj4617: [Wf2016]Spin Doctor
    bzoj3086: Coci2009 dvapravca
    bzoj3745: [Coci2015]Norma
    bzoj1837: [CROATIAN2009]cavli 凸包1
  • 原文地址:https://www.cnblogs.com/rolight/p/3928120.html
Copyright © 2020-2023  润新知