lightoj 1422 Halloween Costumes 区间DP

的确挺神奇的一道题,跟lyc讨论了一会才想清楚正确性。

用dp[x][y]表示完成[x,y]这些舞会至少需要多少衣服。注意这里dp的定义很明确,就是只完成[x,y],之前不需要穿衣服,之后也不需要穿衣服。

那么对应的,答案应该就是dp[1][n]。

我们考虑转移,这道题中,唯一能优化的地方,无非就是我穿了一件衣服,我没脱,过一会又用上了。

那么如果c[x] == c[y]的话,dp[x][y] == dp[x][y - 1],因为最后一件衣服c[y]没用得着重新穿,直接用的c[x]。这里面x,y都是边界,最里面一直藏个衣服显然不影响我中间怎么倒腾。

除了这个情况以外,还有两个情况,一个是我把c[x]脱了,那么dp[x][y] = dp[x][x] + dp[x + 1][y]了。还有一个情况就是我把c[x]留着,等到[x,y]中的某个k正好露出来,用完再脱掉。

两个情况可以用一个for循环统一起来。

这道题,感觉最大的一个体会还是,要搞清楚DP的定义,我只考虑[x,y]部分,那就不去管外面有没有影响,只要每一层的转移和考虑都是周全的,那就没有问题。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 10000000;
int dp[110][110],T,n,cnt,c[110];
int dfs(int l,int r)
{
    if (dp[l][r] != -1)
        return dp[l][r];
    int minn = inf;
    if (c[l] == c[r])
        minn = min(minn,dfs(l,r - 1));
    for (int k = l;k <= r - 1;k++)
        if (c[l] == c[k])
            minn = min(minn,dfs(l,k) + dfs(k + 1,r));
    return dp[l][r] = minn;
}
int main()
{
    for (scanf("%d",&T);T;T--)
    {
        memset(dp,-1,sizeof(dp));
        scanf("%d",&n);
        for (int i = 1;i <= n;i++)
            dp[i][i] = 1;
        for (int i = 1;i <= n;i++)
            scanf("%d",&c[i]);
        printf("Case %d: %d
",++cnt,dfs(1,n));
    }
    return 0;
}
心之所动 且就随缘去吧
原文地址:https://www.cnblogs.com/iat14/p/12008357.html