UVA - 10118 Free Candies(dfs+记忆化搜索)

思路参考了这篇博客:http://www.cnblogs.com/kedebug/archive/2013/04/07/3006493.html

题意:

有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果,
如果篮子里有两个相同的糖果,那么就可以把这两个(一对)糖果放进自己的口袋里,问最多能拿走多少对糖果。糖果种类最多20种.

思路:

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

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

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

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

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 45;
bool vis[N];
int n;
int piles[N][4] , top[4] ,dp[N][N][N][N];
int dps(int cur) {
    int &ans = dp[top[0]][top[1]][top[2]][top[3]];
    if(ans != -1) {
        return ans;
    }else if(cur == 5) {
        return ans = 0;
    }
    int tmp = 0;
    for(int i = 0; i < 4; i++) {
        if(top[i] < n) {
            int color = piles[top[i]][i];
            top[i]++;
            if(vis[color]) {
                vis[color] = false;
                tmp = max(tmp, dps(cur-1)+1);
                vis[color] = true;
            }else {
                vis[color] = true;
                tmp = max(tmp, dps(cur+1));
                vis[color] = false;
            }
            top[i]--;
        }
    }
    return ans = tmp;
}
int main() {
    while(scanf("%d",&n) != EOF && n) {
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < 4; j++) {
                scanf("%d",&piles[i][j]);
            }
        }
        memset(vis,false,sizeof(vis));
        memset(dp, -1,sizeof(dp));
        top[0] = top[1] = top[2] = top[3] = 0;
        printf("%d\n",dps(0));
    }
    return 0;
}

你可能感兴趣的:(uva,10gen)