第一道記憶化搜尋。
阿新 • • 發佈:2018-11-27
題目大意:有4堆糖果,每堆有n個,有一隻最多能容5個糖果的籃子。現在,要把糖果放到籃子裡,如果籃子中有相同顏色的糖果,放的人就可以拿到自己的口袋。如果放的人足夠聰明,問他最多能得到多少對糖果。
題目分析:很顯然的多階段決策。定義dp(a,b,c,d)為每堆糖果分別拿掉a、b、c、d塊之後最多能獲得得糖果對數。則決策有4個,以第一堆為例,狀態轉移方程為:dp(a,b,c,d)=dp(a+1,b,c,d) (如果拿掉第一堆的第a+1個不會產生相同顏色)、dp(a,b,c,d)=dp(a+1,b,c,d)+1 (如果拿掉第一堆的第a+1個會產生相同顏色)。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <string> #include <string.h> #include <cmath> #include <sstream> using namespace std; const int maxn = 50; int dp[maxn][maxn][maxn][maxn]; int pile[maxn][4], p[6]; int n; int dfs(int num, int status) { int &ans = dp[p[0]][p[1]][p[2]][p[3]]; //修改dp陣列時,同時修改ans。 if (ans != -1) return ans; if (num == 5) return 0; ans = 0; for (int i = 0; i < 4; i++) { if (p[i] < n) { int st = 1<<pile[p[i]][i]; p[i]++; if (status&st)//用與運算表示有相同顏色的糖果 ans = max(ans, dfs(num - 1, status^st) + 1); else ans = max(ans, dfs(num + 1, status^st));//異或表示放入取出一個糖果後的狀態 p[i]--; } } return ans; } int main() { while (cin >> n&&n!=0) { for (int i = 0; i < n; i++) { for (int j = 0; j < 4; j++) { cin >> pile[i][j]; } } memset(dp, -1, sizeof(dp)); memset(p, 0, sizeof(p)); cout << dfs(0, 0) << endl;; } }
在運算籃子裡有沒有相同種類糖果時,運用異或跟與的特性:
預處理:int st = 1<<pile[p[i]][i];
statued:1^2,st=3;
statue:1^2&3==false;
statued :1^2,st=3;
statue:1^2&3==true;但是按照提議要求,籃子裡有不同糖果應該為false;