233

 1 /*
 2 题意是给4堆(堆的高度小于等于40)有颜色(颜色的种类小于等于20)的物品,你有一个篮子最多能装5件物品,每次从这4堆物品里面
 3 任取一件物品放进篮子里,但是取每堆物品时,必须先取上面的物品,才能取下面的物品,如果发现篮子里
 4 的两种物品的颜色一样,那么把这两种物品拿出来,问最后最多能拿出多少对物品?;
 5 解题思路:记忆化搜索+dp+状态压缩;
 6 因为40×40×40×40不会太大,所以可以用dp[x[1]][x[2]][x[3]][x[4]]记录搜索的状态;
 7 dp[x[1]][x[2]][x[3]][x[4]]记录4堆分别从x[1],x[2],x[3],x[4]处往下取所获得的最大值;
 8 因为颜色种类最多20种,可以对篮子里的物品颜色用每个位来存储,所以就用到了位状态压缩;
 9 Sample Input
10 5
11 1 2 3 4
12 1 5 6 7
13 2 3 3 3
14 4 9 8 6
15 8 7 2 1
16 Sample Output
17 8
18 */
19 #include<iostream>
20 #include<cstring>
21 #include<cstdio>
22 using namespace std;
23 int dp[45][45][45][45];
24 int map[45][5];
25 int x[5];
26 int n;
27 
28 int dfs(int basket,int num){        //颜色状态,篮子里的水果数目
29     if(dp[x[1]][x[2]][x[3]][x[4]]!=-1){
30         return dp[x[1]][x[2]][x[3]][x[4]];
31     }
32     int sum=0,MAX=0,bit;
33     for(int i=1;i<=4;i++){
34         x[i]++;
35         if(x[i]<=n){
36             bit=(1<<map[x[i]][i]);
37             if(basket&bit){         //找到颜色相同的
38                 sum=dfs(basket&(~bit),num-1)+1;     //删去该颜色,注意是拿多少对,所以只要+1即可
39             }else if(num<4){        //如果数目为4的话,放一种后即失败,所以目前最多只能存在3个
40                 sum=dfs(basket|bit,num+1);
41             }
42         }
43         if(sum>MAX)MAX=sum;
44         x[i]--;
45     }
46     return dp[x[1]][x[2]][x[3]][x[4]]=MAX;
47 }
48 
49 
50 
51 int main(){
52     while(~scanf("%d",&n)&&n){
53         for(int i=1;i<=n;i++)
54             for(int j=1;j<=4;j++)
55                 scanf("%d",&map[i][j]);
56         memset(dp,-1,sizeof(dp));
57         x[1]=x[2]=x[3]=x[4]=0;
58         int ans=dfs(0,0);
59         printf("%d
",ans);
60     }
61     return 0;
62 }
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4882612.html