[UVa] 10118 Free Candies

传送门

Door

题意翻译

桌上有4堆糖果,每堆有N(N≤40)颗。佳佳有一个最多可以装5颗糖的小篮子。他每次 选择一堆糖果,把最顶上的一颗拿到篮子里。如果篮子里有两颗颜色相同的糖果,佳佳就把 它们从篮子里拿出来放到自己的口袋里。如果篮子满了而里面又没有相同颜色的糖果,游戏 结束,口袋里的糖果就归他了。当然,如果佳佳足够聪明,他有可能把堆里的所有糖果都拿 走。为了拿到尽量多的糖果,佳佳该怎么做呢?

来自:刘汝佳《算法竞赛入门经典》

题目解析

记忆化搜索。

直接dp的话怕是要MLE,所以开一个dp[a][b][c][d]来记录一下在四堆糖的状态下的最优解。

开一个col数组记录篮子里有没有这个颜色的糖,因为有两个糖就会消掉,所以每次取反就好了。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 40 + 5;
const int MAXM = 20 + 5;

int n;
int dp[MAXN][MAXN][MAXN][MAXN];
int t[5],pile[5][MAXN];
bool col[MAXN];

int dfs(int num, bool basket[]) {
    if(dp[t[1]][t[2]][t[3]][t[4]] != -1) {
        return dp[t[1]][t[2]][t[3]][t[4]];
    }
    if(num == 5) return dp[t[1]][t[2]][t[3]][t[4]] = 0;
    int res = 0;
    for(int i = 1;i <= 4;i++) {
        if(t[i] == n) continue;
        t[i]++;
        if(col[pile[i][t[i]]]) {
            col[pile[i][t[i]]] = false;
            res = max(res,dfs(num-1,col)+1);
            col[pile[i][t[i]]] = true;
        } else {
            col[pile[i][t[i]]] = true;
            res = max(res,dfs(num+1,col));
            col[pile[i][t[i]]] = false;
        }
        t[i]--;
    }
    return dp[t[1]][t[2]][t[3]][t[4]] = res;
}

inline void clean() {
    memset(dp,-1,sizeof(dp));
    memset(t,0,sizeof(t));
    memset(col,0,sizeof(col));
    return;
}

int main() {
    while(true) {
        scanf("%d",&n);
        if(!n) return 0;
        for(int i = 1;i <= n;i++) {
            for(int j = 1;j <= 4;j++) {
                scanf("%d",&pile[j][i]);
            }
        }
        clean();
        printf("%d
",dfs(0,col));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/floatiy/p/9853020.html