題目:UVA - 10118Free Candies(記憶化搜索)
題目大意:給你四堆糖果,每個糖果都有顏色。每次你都只能拿任意一堆最上面的糖果,放到自己的籃子裡。如果有兩個糖果顏色相同的話,就可以將這對糖果放進自己的口袋。自己的籃子最多只能裝5個糖果,如果滿了,游戲就結束了。問你能夠得到的最多的糖果對數。
解題思路:這題想了好久,好不容易把狀態想對了,結果腦子發熱,又偏離了方向。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#include 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; }