Free Candies(记忆化搜索)

  Little Bob is playing a game. He wants to win some candies in it - as many as possible.
  There are 4 piles, each pile contains N candies. Bob is given a basket which can hold at most 5 candies. Each time, he puts a candy at the top of one pile into the basket, and if there’re two candies of the same color in it ,he can take both of them outside the basket and put them into his own pocket. When the basket is full and there are no two candies of the same color, the game ends. If the game is played perfectly, the game will end with no candies left in the piles.
例子
Input
  The input will contain no more than 10 test cases. Each test case begins with a line containing a single integer n(1<=n<=40) representing the height of the piles. In the following n lines, each line contains four integers xi1,xi2,xi3,xi4 (in the range 1…20). Each integer indicates the color of the corresponding candy. The test case containing n=0 will terminate the input, you should not give an answer to this case.
Output
  Output the number of pairs of candies that the cleverest little child can take home. Print your answer in a single line for each test case.
Sample Input
5
1 2 3 4
1 5 6 7
2 3 3 3
4 9 8 6
8 7 2 1
1
1 2 3 4
3
1 2 3 4
5 6 7 8
1 2 3 4
0
Sample Output
8
0
3

题意:

  有4根竖直的管子,每个管子里有n颗糖果叠成一堆,有一个篮子,最多可以放5颗糖果。每次可以取走任意一个管子的最上方的一颗糖果放到篮子里,若篮子里有两颗糖的颜色相同,可以将这一对糖果放进口袋。求最多可以放多少对糖果到口袋里。
  很明显符合记忆化搜索的特性,既然有四根管子,那么就应该对应着dp[50][50][50][50],对应的意思是当四根管子分别处在这种状态时口袋里的糖数,所以dp数组的初始化为 -1。从中还能看出要记录每根管子的状态,那么一个a[4]就可以了。

记忆化搜索:

  第一步、如果dp[a[0]][a[1]][a[2]][a[3]] != -1 那么说明在这种情况下,已经递推过口袋中的糖数,所以就直接return dp数值;
  第二步、既然是四根管子,那么就要有一个for循环来依次递推,每次a[i]++,就代表着从第i根管子上取下糖果,这是需要判断是否有相同颜色的糖果存在于篮子里,这里用一个vil数组来标记:
  如果 vil[糖果]==ture,就代表在里面,那么就是 ans = max(ans,dfs(k-1)+1);(k是篮子里的糖数)
  反之 ans = max(ans,dfs(k+1));
  第三步、回溯

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int a[50][4];
bool vil[200];
int p[4],n;
int dp[50][50][50][50];
int dfs(int m)
{
    int &ans = dp[p[0]][p[1]][p[2]][p[3]];
    if(ans!=-1) return ans;
    ans = 0;
    if(m>=5) return ans;	//篮子已满
    for(int i=0;i<4;i++){
        if(p[i]>=n) continue;	//管子上的糖果放完
        ++p[i];
        if(vil[a[p[i]][i]]){
            vil[a[p[i]][i]] = false;
            ans = max(ans,dfs(m-1)+1);
            vil[a[p[i]][i]] = true;	//回溯
        }
        else{
            vil[a[p[i]][i]] = true;
            ans = max(ans,dfs(m+1));
            vil[a[p[i]][i]] = false;	//回溯
        }
        --p[i];		//回溯
    }
    return ans;
}
int main(void)
{
    while(scanf("%d",&n),n){
        for(int i=1;i<=n;i++){
            for(int j=0;j<4;j++){
                scanf("%d",&a[i][j]);
            }
        }
        memset(p,0,sizeof(p));
        memset(dp,-1,sizeof(dp));
        memset(vil,false,sizeof(vil));
        printf("%d\n",dfs(0));
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃夭丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值