一直觉得这题因为有总量限制,是不能用母函数解的,今天偶然发现原来是可以的,记录一下。
只要搞母函数的时候多开一维来表示用了多少个硬币就好了,其实就是目标状态是二维的母函数
类似于 假设我现在要处理的面值是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\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,¬e = 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; }
AOJ 169 找零钱 DP OR 母函数,布布扣,bubuko.com
时间: 2024-10-19 00:51:51