转载自:http://www.hankcs.com/program/cpp/poj-1742-coins.html
dp[i][j] := 用前i种硬币凑成j时第i种硬币最多能剩余多少个(-1表示配不出来)
如果dp[i - 1][j] >= 0(前i-1个数可以凑出j,那么第i个数根本用不着)直接为C[i]
dp[i][j] = 如果j < A[i]或者dp[i][j - a[i]] <=0 (面额太大或者在配更小的数的时候就用光了)-1
其他(将第i个数用掉一个) dp[i][j-a[i]] - 1
#include <iostream>
#include <algorithm>
using namespace std;
int dp[100 + 16][100000 + 16]; // dp[i][j] := 用前i种硬币凑成j时第i种硬币最多能剩余多少个
int A[100 + 16];
int C[100 + 16];
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n, m;
while(cin >> n >> m && n > 0)
{
memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
for (int i = 0; i < n; ++i)
{
cin >> A[i];
}
for (int i = 0; i < n; ++i)
{
cin >> C[i];
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j <= m; ++j)
{
if (dp[i][j] >= 0)
{
dp[i + 1][j] = C[i];
}
else if (j < A[i] // 用一个就超出,不能用
|| dp[i + 1][j - A[i]] <= 0) // 连凑比j小的数的时候都用完了,此时更加用完了
{
dp[i + 1][j] = -1;
}
else
{
dp[i + 1][j] = dp[i + 1][j - A[i]] - 1; // 用上了一个第i个硬币
}
}
}
int answer = count_if(dp[n] + 1, dp[n] + 1 + m , bind2nd(greater_equal<int>(), 0)); // 总额0不算在答案内
cout << answer << endl;
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return 0;
}
///////////////////////////End Sub//////////////////////////////////
但是这样会MLE,所以需要减少一维
dp[j] := 在第i次循环时之前表示用前i-1种硬币凑成j时第i种硬币最多能剩余多少个(-1表示配不出来),循环之后就表示第i次的状态
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int dp[100000 + 16]; // dp[i][j] := 用前i种硬币凑成j时第i种硬币最多能剩余多少个
int A[100 + 16];
int C[100 + 16];
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n, m;
while(cin >> n >> m && n > 0)
{
memset(dp, -1, sizeof(dp));
dp[0] = 0;
for (int i = 0; i < n; ++i)
{
cin >> A[i];
}
for (int i = 0; i < n; ++i)
{
cin >> C[i];
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j <= m; ++j)
{
if (dp[j] >= 0)
{
dp[j] = C[i];
}
else if (j < A[i] // 用一个就超出,不能用
|| dp[j - A[i]] <= 0) // 连凑比j小的数的时候都用完了,此时更加用完了
{
dp[j] = -1;
}
else
{
dp[j] = dp[j - A[i]] - 1; // 用上了一个第i个硬币
}
}
}
int answer = count_if(dp + 1, dp + 1 + m , bind2nd(greater_equal<int>(), 0)); // 总额0不算在答案内
cout << answer << endl;
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return 0;
}