假设在当前状态我们第i堆糖果分别取了cnt[i]个,那么篮子里以及口袋里糖果的个数都是可以确定下来的。
所以就可以使用记忆化搜索。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 45; 7 const int maxm = 4; 8 9 int n; 10 11 int candy[maxn][maxm]; 12 int d[maxn][maxn][maxn][maxn]; 13 14 struct State 15 { 16 int tot; //篮子里糖果的数量 17 int cnt[4]; //第i堆糖果取了cnt[i]个 18 int kind[21]; //篮子里第i中糖果有ind[i]个 19 }; 20 21 int dp(State s) 22 { 23 int& ans = d[s.cnt[0]][s.cnt[1]][s.cnt[2]][s.cnt[3]]; 24 if(ans >= 0) return ans; 25 if(s.tot == 5) return ans = 0; 26 27 ans = 0; 28 for(int i = 0; i < 4; i++) 29 { 30 if(s.cnt[i] == n) continue; 31 int color = candy[s.cnt[i]][i]; 32 s.cnt[i]++; 33 if(s.kind[color]) 34 { 35 s.tot--; 36 s.kind[color] = 0; 37 ans = max(ans, dp(s) + 1); 38 s.tot++; 39 s.kind[color] = 1; 40 41 } 42 else 43 { 44 s.tot++; 45 s.kind[color] = 1; 46 ans = max(ans, dp(s)); 47 s.tot--; 48 s.kind[color] = 0; 49 } 50 s.cnt[i]--; 51 } 52 return ans; 53 } 54 55 int main() 56 { 57 while(scanf("%d", &n) == 1 && n) 58 { 59 for(int i = 0; i < n; i++) 60 for(int j = 0; j < 4; j++) scanf("%d", &candy[i][j]); 61 62 State s; 63 s.tot = 0; 64 for(int i = 0; i < 4; i++) s.cnt[i] = 0; 65 for(int i = 1; i <= 20; i++) s.kind[i] = 0; 66 memset(d, -1, sizeof(d)); 67 printf("%d ", dp(s)); 68 } 69 70 return 0; 71 }