题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1514
思路:orz...大牛讲的太妙了:
题意是给4堆(堆的高度小于等于40)有颜色(颜色的种类小于等于20)的物品,你有一个篮子最多能装5件物品,每次从这4堆物品里面
任取一件物品放进篮子里,但是取每堆物品时,必须先取上面的物品,才能取下面的物品,如果发现篮子里
的两种物品的颜色一样,那么把这两种物品拿出来,问最后最多能拿出多少对物品?;
解题思路:记忆化搜索+dp+状态压缩;
因为40×40×40×40不会太大,所以可以用dp[x[1]][x[2]][x[3]][x[4]]记录搜索的状态;
dp[x[1]][x[2]][x[3]][x[4]]记录4堆分别从x[1],x[2],x[3],x[4]处往下取所获得的最大值;
因为颜色种类最多20种,可以对篮子里的物品颜色用每个位来存储,所以就用到了位状态压缩;
最后就是一步一步的试探搜索了。。。
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int dp[45][45][45][45]; 6 int map[45][5]; 7 int x[5]; 8 int n; 9 10 int dfs(int basket,int num){ 11 if(dp[x[1]][x[2]][x[3]][x[4]]!=-1){ 12 return dp[x[1]][x[2]][x[3]][x[4]]; 13 } 14 int sum=0,MAX=0,bit; 15 for(int i=1;i<=4;i++){ 16 x[i]++; 17 if(x[i]<=n){ 18 bit=(1<<map[x[i]][i]); 19 if(basket&bit){ 20 sum=dfs(basket&(~bit),num-1)+1; 21 }else if(num<4){ 22 sum=dfs(basket|bit,num+1); 23 } 24 } 25 if(sum>MAX)MAX=sum; 26 x[i]--; 27 } 28 return dp[x[1]][x[2]][x[3]][x[4]]=MAX; 29 } 30 31 32 33 int main(){ 34 while(~scanf("%d",&n)&&n){ 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=4;j++) 37 scanf("%d",&map[i][j]); 38 memset(dp,-1,sizeof(dp)); 39 x[1]=x[2]=x[3]=x[4]=0; 40 int ans=dfs(0,0); 41 printf("%d\n",ans); 42 } 43 return 0; 44 } 45 46 47