[UVa 1625]Color Length

Problem Description

这里写图片描述

My Problem Report

这是道非常值得总结的题。通过这道题我对两个概念的理解加深了很多:

  1. 无后效性原则
  2. 最优子结构

在做动态规划的时候,我们需要明白一点,就是当前状态一定是由过去的状态(也就是最优子结构)转移而来的,而不是说过去的状态影响了现在的状态。我们在对状态进行转移时,要充分意识到三点:

  1. 过去的状态一定是最优的,我们可以“充分相信”它们
  2. 不是所有过去的状态都能用上,我们需要对他们进行一些筛选,这也就是所谓的”决策“
  3. 在作出决策后,转移状态还需要付出一定的代价(这里的代价并不是指时间效率上的),也可以这样归纳:

now=best{past}+cost

或者有时候我们在决策时就应该考虑不同的代价

now=best{past+cost}

我们再回到这道题上。我们可以简单得用f[i][j]来表示序列1取了i个,序列2取了j个时,对最终答案造成的影响。可能读到这里会感觉这样定义状态太模糊了,但若过仔细阅读以下《入门经典》上的题解,会发现这样的解释其实是比较恰当的。
或者我们可以换个说法:

f[i][j]表示的是,当序列1取了i个,序列2取了j个时,对“已经出现,但还没有结束的颜色”的影响

所以我们可以发现,这个状态看似很简单,但我们要得到它实际上是要对模型进行一些深入分析的,而且很多时候还会寻找一些技巧。这也就是DP建模的核心和难点。
我们在接着往下看,如果我们不做任何预处理的话,要去计算状态转移中的cost(见前面的式子,这里表示“已经出现,但还没有结束的颜色”的数量),需要花费O(nm)的时间,但显然这里我们是可以通过预处理来使这个计算的代价降为O(1)。

My Source Code

//  Created by Chlerry in 2015.
//  Copyright (c) 2015 Chlerry. All rights reserved.
//

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define Size 5010
#define ll long long
#define mk make_pair
#define pb push_back
#define mem(array, x) memset(array,x,sizeof(array))
typedef pair<int,int> P;

int starta[26],startb[26],enda[26],endb[26],f[Size][Size],lena,lenb;
char a[Size],b[Size];
int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
while(T--)
{
    scanf("%s %s",a,b);lena=strlen(a),lenb=strlen(b);
    for(int i=0;i<26;i++)
        starta[i]=startb[i]=INT_MAX,enda[i]=endb[i]=INT_MIN;
    for(int i=0;i<lena;i++)
    {
        if(starta[a[i]-'A']==INT_MAX)
            starta[a[i]-'A']=i+1;
        enda[a[i]-'A']=i+1;
    }
    for(int i=0;i<lenb;i++)
    {
        if(startb[b[i]-'A']==INT_MAX)
            startb[b[i]-'A']=i+1;
        endb[b[i]-'A']=i+1;
    }
    for(int i=0;i<=lena;i++)
        for(int j=0;j<=lenb;j++)
        {
            f[i][j]=0;
            for(int k=0;k<26;k++)
                if( (i>=starta[k] || j>=startb[k]) && (i<enda[k] || j<endb[k]) )
                    f[i][j]++;
            if(i==0 && j==0)
                continue;
            else if(i==0)
                f[i][j]+=f[i][j-1];
            else if(j==0)
                f[i][j]+=f[i-1][j];
            else 
                f[i][j]+=min(f[i-1][j],f[i][j-1]);
        }
    printf("%d\n",f[lena][lenb]);
}
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值