传送门
题意翻译
桌上有4堆糖果,每堆有N(N≤40)颗。佳佳有一个最多可以装5颗糖的小篮子。他每次 选择一堆糖果,把最顶上的一颗拿到篮子里。如果篮子里有两颗颜色相同的糖果,佳佳就把 它们从篮子里拿出来放到自己的口袋里。如果篮子满了而里面又没有相同颜色的糖果,游戏 结束,口袋里的糖果就归他了。当然,如果佳佳足够聪明,他有可能把堆里的所有糖果都拿 走。为了拿到尽量多的糖果,佳佳该怎么做呢?
来自:刘汝佳《算法竞赛入门经典》
题目解析
记忆化搜索。
直接dp的话怕是要MLE,所以开一个dp[a][b][c][d]来记录一下在四堆糖的状态下的最优解。
开一个col数组记录篮子里有没有这个颜色的糖,因为有两个糖就会消掉,所以每次取反就好了。
Code
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 40 + 5; const int MAXM = 20 + 5; int n; int dp[MAXN][MAXN][MAXN][MAXN]; int t[5],pile[5][MAXN]; bool col[MAXN]; int dfs(int num, bool basket[]) { if(dp[t[1]][t[2]][t[3]][t[4]] != -1) { return dp[t[1]][t[2]][t[3]][t[4]]; } if(num == 5) return dp[t[1]][t[2]][t[3]][t[4]] = 0; int res = 0; for(int i = 1;i <= 4;i++) { if(t[i] == n) continue; t[i]++; if(col[pile[i][t[i]]]) { col[pile[i][t[i]]] = false; res = max(res,dfs(num-1,col)+1); col[pile[i][t[i]]] = true; } else { col[pile[i][t[i]]] = true; res = max(res,dfs(num+1,col)); col[pile[i][t[i]]] = false; } t[i]--; } return dp[t[1]][t[2]][t[3]][t[4]] = res; } inline void clean() { memset(dp,-1,sizeof(dp)); memset(t,0,sizeof(t)); memset(col,0,sizeof(col)); return; } int main() { while(true) { scanf("%d",&n); if(!n) return 0; for(int i = 1;i <= n;i++) { for(int j = 1;j <= 4;j++) { scanf("%d",&pile[j][i]); } } clean(); printf("%d ",dfs(0,col)); } return 0; }