题目大意:给出4个硬币的价值和个数限制,求有多少种方法凑成S块钱。
思路:很巧妙的一种想法,用到了4这个非常小的数字。我们可以先不管每个硬币的个数限制,然后跑一次完全背包。之后把不符合的情况去除就行了。方法是,先减去一种硬币超限的数目,然后加上两种硬币超限的数目,然后减去三种硬币超限的数目,然后加上四种硬币超限的个数。当然代码就很丑了。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define P(i) (c[i] * (l[i] + 1)) using namespace std; int c[5],l[5],s; int cnt; long long f[MAX],ans; int main() { for(int i = 1; i <= 4; ++i) scanf("%d",&c[i]); cin >> cnt; for(int i = 1; i <= cnt; ++i) { for(int j = 1; j <= 4; ++j) scanf("%d",&l[j]); scanf("%d",&s); memset(f,0,sizeof(f)); f[0] = 1; for(int _i = 1; _i <= 4; ++_i) for(int j = c[_i]; j <= s; ++j) f[j] += f[j - c[_i]]; ans = f[s]; for(int _i = 1; _i <= 4; ++_i) if(s - P(_i) >= 0) ans -= f[s - P(_i)]; if(s - P(1) - P(2) >= 0) ans += f[s - P(1) - P(2)]; if(s - P(2) - P(3) >= 0) ans += f[s - P(2) - P(3)]; if(s - P(3) - P(4) >= 0) ans += f[s - P(3) - P(4)]; if(s - P(2) - P(4) >= 0) ans += f[s - P(2) - P(4)]; if(s - P(1) - P(3) >= 0) ans += f[s - P(1) - P(3)]; if(s - P(1) - P(4) >= 0) ans += f[s - P(1) - P(4)]; if(s - P(1) - P(2) - P(3) >= 0) ans -= f[s - P(1) - P(2) - P(3)]; if(s - P(2) - P(3) - P(4) >= 0) ans -= f[s - P(2) - P(3) - P(4)]; if(s - P(1) - P(3) - P(4) >= 0) ans -= f[s - P(1) - P(3) - P(4)]; if(s - P(1) - P(2) - P(4) >= 0) ans -= f[s - P(1) - P(2) - P(4)]; if(s - P(1) - P(2) - P(3) - P(4) >= 0) ans += f[s - P(1) - P(2) - P(3) - P(4)]; printf("%lld\n",ans); } return 0; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/41808551