题目:uva10626 - Buying Coke(记忆话搜索)
题目大意:给你3种价值的硬币, 1, 5, 10现在要求你取自动售卖机买可乐,一瓶可乐价值8,给你要求买的可乐的数目,和三种硬币的数目,问你最少需要投多少硬币。自动售卖机会根据你投入的钱来找零,可以的话找出的零钱硬币会最少。
解题思路: 这题之前没有想到可乐的已经购买瓶数是隐含在剩余的硬币情况中,换句话说就是你买了多少瓶可乐,不论用什么方式买,剩余的硬币的情况总能反映买了多少瓶可乐。所
以数组开3维就可以了。而且要注意还有 1 个 10 和 3 个1 买 1 coke 找 1个 5的情况。 转移状态(2 个 5 找 2个 1) ( 1个10 找 2个1 ) (1个5 3个1 找 0) (1个10 3个 1 找1 个5)最后的8个1 可以放在最后考虑,因为是最坏的情况才用这个,所以当5和10的硬币都没有了,再用1来买。
代码:
#include <cstdio>
#include <cstring>
const int N1 = 705;
const int N2 = 155;
const int N3 = 55;
const int INF = 0x3f3f3f3f;
int f[N1][N2][N3];
void init () {
for (int i = 0; i < N1; i++)
for (int k = 0; k < N2; k++)
for (int l = 0; l < N3; l++)
f[i][k][l] = INF;
}
int Min (const int a, const int b) { return a < b? a: b;}
int DP (int c, int n1, int n2, int n3) {
// printf ("%d %d %d %d\n", c, n1, n2, n3);
int& ans = f[n1][n2][n3];
if (ans != INF)
return ans;
if (c == 0)
return ans = 0;
if (!n2 && !n3)
return ans = 8 * c;
if (n3)
ans = Min (ans, DP(c - 1, n1 + 2, n2, n3 - 1) + 1);
if (n2 >= 2)
ans = Min (ans, DP(c - 1, n1 + 2, n2 - 2, n3) + 2);
if (n2 && n1 >= 3)
ans = Min (ans, DP(c - 1, n1 - 3, n2 - 1, n3) + 4);
if (n3 && n1 >= 3)
ans = Min (ans, DP(c - 1, n1 - 3, n2 + 1, n3 - 1) + 4);
return ans;
}
int main () {
int t;
int c, n1, n2, n3;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d%d%d", &c, &n1, &n2, &n3);
init ();
printf ("%d\n", DP(c, n1, n2, n3));
}
return 0;
}