UVa 10118 Free Candies(记忆化搜索经典)

题意:

有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果,

如果篮子里有两个相同的糖果,那么就可以把这两个(一对)糖果放进自己的口袋里,问最多能拿走多少对糖果。糖果种类最多20种. 

(黑书 148 免费糖果)

思路:

1. 这一题有点逆向思维的味道,dp[a, b, c, d] 表示从每堆中分别拿 a, b, c, d 个时,最多能拿多少个糖果;

2. 注意一点:当拿到 a, b, c, d 时,不能再拿了,此时结果肯定就会固定。利用这一点性质,采用记忆化搜索能有效的减少重复子结构的计算;

3. 题目是只有 0 0 0 0 这一个出发点的,根据这个出发点进行深搜,最终得出结果。

4. 本题可谓是深搜 + 记忆化搜索的经典,状态不是那么明显,子结构也不是那么好抽象,因为转移的末状态并不是固定的,是在不断的搜索中求出来的;

 

#include <iostream>

#include <algorithm>

#include <cstdlib>

#include <cstring>

#include <cstdio>

using namespace std;



const int MAXN = 41;

int pile[4][MAXN], dp[MAXN][MAXN][MAXN][MAXN];

int n, top[4];



int dfs(int count, bool hash[]) {

    if (dp[top[0]][top[1]][top[2]][top[3]] != -1)

        return dp[top[0]][top[1]][top[2]][top[3]];



    if (count == 5) 

        return dp[top[0]][top[1]][top[2]][top[3]] = 0;



    int ans = 0;

    for (int i = 0; i < 4; i++) {

        if (top[i] == n) continue;

        int color = pile[i][top[i]];

        top[i] += 1;

        if (hash[color]) {

            hash[color] = false;

            ans = max(ans, dfs(count-1, hash) + 1);

            hash[color] = true;

        } else {

            hash[color] = true;

            ans = max(ans, dfs(count+1, hash));

            hash[color] = false;

        }

        top[i] -= 1;

    }

    return dp[top[0]][top[1]][top[2]][top[3]] = ans;

}



int main() {

    while (scanf("%d", &n) && n) {

        for (int i = 0; i < n; i++)

            for (int j = 0; j < 4; j++)

                scanf("%d", &pile[j][i]);

        bool hash[25];

        memset(dp, -1, sizeof(dp));

        memset(hash, false, sizeof(hash));

        top[0] = top[1] = top[2] = top[3] = 0;

        printf("%d\n", dfs(0, hash));

    }

    return 0;

}

你可能感兴趣的:(free)