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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM