LightOJ 1422 Halloween Costumes (区间dp)

题意和思路转自https://blog.csdn.net/yyyy_h/article/details/50557550

题意:

告诉有n场晚会中需要穿的衣服,衣服是可以套在其他衣服外面的,也就是说如果顺序为 1 2 1,那么可以将2套在1外面,第三场晚会需要穿1的时候把2脱掉即可,这样就只需要穿两次衣服。

题目是再告诉了顺序之后需要求出在某种序列下最少需要穿多少次衣服。


样例 1 2 1 2: ①穿1   ②穿2  ③脱2  ④穿2      或者     ①穿1   ②脱1穿2  ③穿1  ④脱1    均输出  3


思路:

感觉思路比较巧妙,首先我们使用dp[a][b]来表示区间 a~b 的答案,那么对于第 i 件衣服,我们有


①:如果在之后的区间内都不再重复利用这件衣服,那么明显  dp[i][j] = dp[i+1][j] + 1;


②:如果在之后的区间 i+1 ~ j 中存在一件衣服 k 是跟 i 一样的,那么我们便可以考虑是不是可以将i那件衣服在k这个地方重复利用,

那么转移方程为  dp[i][j] = min(dp[i][j] , dp[i][k-1]+dp[k+1][j]);

或者认为k那件衣服是来自于i 转移方程为    dp[i][j] = min(dp[i][j] , dp[i+1][k-1]+dp[k][j]); //这个转移方程和上一个同意,可以任选一个。


#include <bits/stdc++.h>

using namespace std;
#define pb push_back
#define pii pair<int, int>
#define mk make_pair
#define fi first
#define se second
#define ALL(A) A.begin(), A.end()
#define sc(x) scanf("%d", &x)
#define pr(x) printf(#x":%d\n", x)
#define fastio ios::sync_with_stdio(0), cin.tie(0)
#define frein freopen("in.txt", "r", stdin)
#define freout freopen("out.txt", "w", stdout)
#define freout1 freopen("out1.txt", "w", stdout)
#define debug cout<<"???"<<endl
#define mid ((l+r)>>1)
#define lson ((rt)<<1|1)
#define rson (((rt)<<1)+2)
#define ABS(x) ((x)<0?(-(x)):(x))
//#define br puts("")
#define sqr(x) ((x)*(x))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int INF = 0x3f3f3f3f;
//const ll mod = 1e9+7;
//const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const double PI = acos(-1.0);
template<class T> T gcd(T a, T b){if(!b)return a;return gcd(b,a%b);}

const int maxn = 105;

int dp[maxn][maxn], n, a[maxn];

void MIN(int& a, int b){
    a = (a<b)?a:b;
}

int solve(){
    memset(dp, 0, sizeof(dp));
    for(int i = 0; i < n; i++) dp[i][i] = 1;
    for(int len = 2; len <= n; len++){
        for(int l = 0, r = len-1; r < n; l++, r++){
            dp[l][r] = dp[l][r-1]+1;
            for(int j = l; j < r; j++){
                if(a[j] != a[r]) continue;
                MIN(dp[l][r], dp[l][j]+dp[j+1][r-1]);
            }
        }
    }
    return dp[0][n-1];
}

int main(){
    int T; sc(T);
    for(int kase = 1; kase <= T; kase++){
        sc(n);
        for(int i = 0; i < n; i++) sc(a[i]);
        printf("Case %d: %d\n", kase, solve());
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值