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 }