LightOJ 1422 Halloween Costumes(区间dp)

题目链接:
LightOJ 1422 Halloween Costumes
题意:
需要去参加 n 个聚会,每个聚会可能需要穿不同的衣服,用数字编号表示(1100)。如果连续的聚会需要穿的衣服一样,那就不用换衣服,也可以选择在身上的衣服外面再套上新的衣服,但是脱下的衣服不能在用于剩下的聚会的了,问最少需要准备多少件衣服?
数据范围: n100
分析:
先解释下样例。
n=41 2 1 2
意思是第一场和第三场聚会需要穿1号衣服,第二场和第四场聚会需要穿2号衣服,那么可以选择在第一场聚会时穿上1号衣服,在第二场聚会时在1号衣服外面套上2号衣服,在第三场聚会时脱下外面的2号衣服,然后第四场聚会时在套上一件新的2号衣服,那么总共至少3件衣服。
区间 dp
dp[i][j] 表示从第 i 场聚会到第j场聚会最少需要的衣服数量。区间最优可由子区间最优递推得到。可以发现如果把子区间独立看的话,子区间是不存在联系的,但是当合并成父区间时需要考虑第一个首尾位置的数字编号是否相同,如果相同的话那么就可以节省一件衣服,因为可以选择将这件衣服一直保留在最里层,当在第二个区间需要最后一次需要穿上这件衣服时将外面所有的衣服脱掉即可。所以有状态转移方程:

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])(k[i,j))

data[i]=data[j],:dp[i][j].

因为在得到区间 [i,j] 的状态时需要知道区间 [k,j] 状态的最优解并且 ik ,所以关于 i 的循环应是i:n100
初始化: dp[i][j]=inf,dp[i][i]=1
时间复杂度: O(n3)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 110;
const int inf = 0x3f3f3f3f;

int T, n, cases = 0;
int data[MAX_N], dp[MAX_N][MAX_N];

int main()
{
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &data[i]);
        }
        for(int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                dp[i][j] = inf;
            }
        }
        for (int i = 0; i < n; ++i) { dp[i][i] = 1; }
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i; j < n; ++j) {
                for (int k = i; k < j; ++k) {
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
                }
                if(i != j && data[i] == data[j]) dp[i][j]--;
                //if(dp[i][j] == 0) dp[i][j] = 1;
            //  printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
            }
        }
        printf("Case %d: %d\n", ++cases, dp[0][n - 1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值