• LightOJ 1422 Halloween Costumes(区间dp)


    题目大意: 给你n天要穿的衣服,可以套着穿,但是一旦脱下来就不能载穿了,问n天至少需要多少衣服?

    做了两个关于区间dp的题,遇到这个题还是不会做,网上搜了一下,感觉也不难,就是自己想不起来。。。

    思路:dp[i][j]表示从第i天到第j天至少需要多少衣服,那么dp[i][j] = dp[i + 1][j] + 1,这是最坏情况,就是最多的一种,如果后面有跟第i个相同的,那么根本不许要这么多,只需要dp[i+1][j]中就够了,不用加这个1了,因为后面有跟他相同的,考虑第k天,那么就假设第k天与第i天相同,那么dp[i+1][j]就可以表示为dp[i+1][k-1] + dp[k][j], dp[i + 1][k - 1]表示从i+1天到k-1天最小需要,因为这个和k无关,所以不用管里面有没有相同的,但是后面这个dp[k][j]就有用了,就是说必须k天的跟i天的相同才可以这么拆,不然不能拆。所以状态转移方程就有了。dp[i][j]=min(dp[i][j], dp[i + ][k - 1] + dp[k][j]);

    代码如下:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 110;
    const int inf = (1 << 30);
    int dp[maxn][maxn];
    int a[maxn];
    int main()
    {
        int T, n, kase = 0;
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            for (int i = 1; i <= n; i++)//初始化
                for (int j = i; j <= n; j++)
                    dp[i][j] = j - i + 1;
            for (int i = n - 1; i >= 1; i--)//从后往前推
            {
                for (int j = i + 1; j <= n; j++)
                {
                    dp[i][j] = dp[i + 1][j] + 1;
                    for (int k = i + 1; k <= j; k++)
                        if (a[i] == a[k])
                            dp[i][j] = min(dp[i][j], dp[i + 1][k - 1] + dp[k][j]);
                }
            }
            printf("Case %d: %d
    ", ++kase, dp[1][n]);
        }
        return 0;
    }
    View Code

    还有一点需要说明,在dp问题中,循环顺序是非常非常重要的,一定要搞清楚当前状态是从哪个状态过来的。而且从那个状态过来的时候,那个状态一定是计算过的。上面的就是从后往前推。下面还有一种解法,我个人感觉是非常自然的一个解法,就是状态转移方程比较贴切。

    用dp[i][j]表示从第i天到第j天至少需要多少衣服,考虑第j天,如果在第j天的时候需要的衣服在i->j-1天里面如果没有就是dp[i][j] = dp[i][j - 1] + 1; 如果已经有了的话,那么dp[i][j] = dp[i][j - 1]; 假设在第k天和第j天的衣服相同,由于dp[i][j - 1] = dp[i][k] + dp[k + 1][j - 1]; 所以dp[i][j] = dp[i][k] + dp[k+1][j - 1];

    代码如下:

    #include <cstdio>
    #include <iostream>
    
    using namespace std;
    
    const int maxn = 110;
    int dp[maxn][maxn];
    int a[maxn];
    int main()
    {
        int T, n, kase = 0;
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            for (int i = 1; i <= n; i++)
                for (int j = i; j <= n; j++)
                    dp[i][j] = j - i + 1;
            for (int j = 2; j <= n; j++)//区间右端点,顺序枚举
            {
                for (int i = j - 1; i >= 0; i--)//左端点逆序
                {
                    dp[i][j] = dp[i][j - 1] + 1;
                    for (int k = i; k < j; k++)
                        if (a[k] == a[j])
                            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j - 1]);
                }
            }
            printf("Case %d: %d
    ", ++kase, dp[1][n]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    hdu 1159 Common Subsequence(最长公共子序列)
    Codeforces Round #313 (Div. 2)
    cf 558A Lala Land and Apple Trees
    zoj 2193 Window Pains
    poj 2031 Building a Space Station(最小生成树)
    zoj 1060 Sorting It All Out(拓扑排序)
    拓扑排序
    poj 1287 Networking
    zoj 1586 QS Network
    poj 1679 The Unique MST
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4737536.html
Copyright © 2020-2023  润新知