Problem Description
My Problem Report
这是道非常值得总结的题。通过这道题我对两个概念的理解加深了很多:
- 无后效性原则
- 最优子结构
在做动态规划的时候,我们需要明白一点,就是当前状态一定是由过去的状态(也就是最优子结构)转移而来的,而不是说过去的状态影响了现在的状态。我们在对状态进行转移时,要充分意识到三点:
- 过去的状态一定是最优的,我们可以“充分相信”它们
- 不是所有过去的状态都能用上,我们需要对他们进行一些筛选,这也就是所谓的”决策“
- 在作出决策后,转移状态还需要付出一定的代价(这里的代价并不是指时间效率上的),也可以这样归纳:
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;
}