题目:UVA - 10118Free Candies(记忆化搜索)
题目大意:给你四堆糖果,每一个糖果都有颜色。每次你都仅仅能拿随意一堆最上面的糖果,放到自己的篮子里。假设有两个糖果颜色同样的话,就行将这对糖果放进自己的口袋。自己的篮子最多仅仅能装5个糖果,假设满了,游戏就结束了。问你可以得到的最多的糖果对数。
解题思路:这题想了好久,好不easy把状态想对了,结果脑子发热,又偏离了方向。dp【a】【b】【c】【d】:四堆糖果如今在最上面的是哪一个。由于以下的糖果假设确定了,那么接下了无论你怎么取,最优的肯定是仅仅有一种。所以能够把如今剩余的糖果的最多数量加上你之前取的那些糖果你能得到的糖果最多数量,就是要求的最多的糖果对数。
dp【a】【b】【c】【d】 = Max(dp【a + 1】【b】【c】【d】 + 0|1, dp[a][b +1】【c】【d】 + 0|1, dp【a】【b】【c + 1】【d】 + 0|1 , dp【a】【b】【c】【d +1] + 0|1).0 | 1取决于你如今篮子里是否有和我取的那个糖果颜色同样的。相应的篮子里的糖果数量要变化。假设数量等于5了,就说明不能放了,返回0.而且每堆糖果都有最大的数量,取完也是要结束的。这些边界条件要注意.这里发现了一个新的知识:用memcpy的时候假设不是里面的全部数据都要的话,要指明长度,不然可能会出现错误。
代码:
#include <cstdio> #include <cstring> const int N = 42; const int M = 5; const int maxn = 1000005; int candy[N][M]; int top[M];//存放每堆糖果最上面的序号 int f[N][N][N][N]; int n; int Max (const int a, const int b) { return a > b ? a: b; } void init () { memset (f, -1, sizeof (f)); f[n][n][n][n] = 0;//结束状态不论篮子满不满 } bool handle (int r, int c, int k, int *b) {//处理是否有同样的塘果 int *b是篮子,k + 1是里面有的糖果的个数。 int i; for (i = 0; i < k; i++) { if (candy[r][c] == b[i]) break; } if (!k || i == k) { b[k] = candy[r][c]; return false; } else { for (int j = i; j < k - 1; j++) b[j] = b[j + 1]; return true; } } int dfs (int k, int *bket, int a, int b, int c, int d) { int bket1[M * 2]; int& ans = f[a][b][c][d]; if (k >= M)//篮子满了 return 0;//注意这里ans不一定等于0,由于取糖果的顺序不同的话,这个篮子的情况可能不同 if (ans != -1) return ans; top[1] = a; top[2] = b; top[3] = c; top[4] = d; for (int i = 1; i < M; i++) { /*for (int j = 0; j < k; j++) bket1[j] = bket[j];*/ memcpy (bket1, bket, k * sizeof (int));//注意 /*for (int j = 0; j < k; j++) printf ("%d ", bket1[j]); printf ("\n");*/ if (handle (top[i], i, k, bket1)) { top[i]++; if (top[i] <= n) ans = Max (ans, dfs (k - 1, bket1, top[1], top[2], top[3], top[4]) + 1); } else { top[i]++; if (top[i] <= n) ans = Max (ans, dfs (k + 1, bket1, top[1], top[2], top[3], top[4])); } top[i]--; } return ans; } int main () { while (scanf ("%d", &n), n) { for (int i = 0; i < n; i++) for (int j = 1; j < M; j++) scanf ("%d", &candy[i][j]); int b[M * 2]; init (); printf ("%d\n", dfs (0, b, 0, 0, 0, 0)); // printf ("%d\n", f[n][n - 1][0][0]); /* for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { for (int l = 0; l < n; l++) printf ("%d ", f[i][j][k][l]); printf ("\n"); } printf ("\n"); } printf ("\n"); } printf ("\n");*/ } return 0; }