题意:给你cnt[0]个一元硬币,cnt[1]个两元硬币,cnt[2]个五元硬币,问不能凑出来的第一个面额是多少。
分析:不得不说遇到这个题的第一反应是多重背包265ms。一直跑到面额最大的数字,显然肯定能解决。另一种则是抽象成生成函数(母函数)加以解决64ms。
母函数模拟方式:
(1+x+x2+x3+.........xcnt1)∗(1+x2+x4+x6+.........xcnt2)∗(1+x5+x10+x15+............xcnt5)
母函数:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
#define ll long long int
const int maxn = 1e4 + 10;
int val[3] = { 1,2,5 }, cnt[3];
int c1[maxn], c2[maxn], mmax;
int main()
{
while (~scanf("%d%d%d", &cnt[0], &cnt[1], &cnt[2]) && (cnt[0] || cnt[1] || cnt[2]))
{
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
mmax = 0;
for (int i = 0; i < 3; i++) mmax += cnt[i] * val[i];
for (int i = 0; i <= cnt[0]; i++) c1[i] = 1;
for (int i = 1; i < 3; i++) {
for (int j = 0; j <= mmax; j++) {
if (c1[j]) {
for (int k = 0; k <= val[i] * cnt[i]; k += val[i]) {
if (j + k <= mmax) {
c2[j + k] += c1[j];
}
}
}
}
memcpy(c1, c2, sizeof(c1));
memset(c2, 0, sizeof(c2));
}
int i;
for (i = 0; i <= mmax; i++) {
if (c1[i] == 0)
break;
}
printf("%d\n", i);
}
return 0;
}
多重背包:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
#define ll long long int
const int maxn = 1e4 + 10;
//f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]} 多重背包
int val[3] = { 1,2,5 };
int cnt[3]; int mmax;
int dp[maxn];
int main()
{
while (~scanf("%d %d %d", &cnt[0], &cnt[1], &cnt[2]) && (cnt[0] || cnt[1] || cnt[2]))
{
memset(dp, 0, sizeof(dp));
mmax = 0;
for (int i = 0; i < 3; i++)
{
mmax += cnt[i] * val[i];
}
dp[0] = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < cnt[i]; j++)
{
for (int k = mmax; k >= val[i]; k--)
{
dp[k] = (dp[k]+dp[k - val[i]]);
}
}
}
int i;
for (i = 1; i <= mmax; i++)
{
if (dp[i] == 0)
break;
}
printf("%d\n", i);
}
return 0;
}