继续大战dp,一定要把这一关闯过去!
题意分析
这条题目的大意是这样的,问一字符串内最少删去多少的字符使其由给定的若干字符串构成。实际上没看题解我根本想不到这题的dp解法,只能说思维还是太浅薄幼稚了。
具体的dp解法是什么呢?考虑一下我们删去的这个过程。比如说这个式子
throw
thraow
我们要不然删去a,要不然删去 “thraow”。我们怎么知道删去a能够使得这俩个单词匹配的?我们当然是逐字逐字的去匹配了。因此,我们应当是对母串的每一个单字的进行匹配,看看每次删去多少满足最小,然后把他保存起来。因此,我们设立
dp[i]
保存每次删去的最小值——网上有从左往右处理的方法, 不过我没看懂- -以后再分析吧——从右往左去处理。这样,
dp[i]
的意思就是“从i->l删除最少的值。”
有了上面这些思维过程,转移方程就很容易得出了:
dp[i]={dp[i+1]+1dp[cur]+L−cur−i失配在cur处完成匹配
代码
还是老话,dp的很多题目的代码是雷同的- -(其实就是自己菜的一个借口
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;
typedef unsigned long long ull;
int dp[305];
int main()
{
int w,l;
while(cin>>w>>l)
{
string wstr; cin>>wstr;
vector<string> lstr;
for(int i=1;i<=w;++i)
{
string tmp; cin>>tmp;
lstr.push_back(tmp);
}
dp[l]=0;
for(int i=l-1;i>=0;--i)
{
dp[i]=dp[i+1]+1;
//printf("dp[%d]=%d.\n",i,dp[i+1]+1);
for(int j=0;j!=w;++j)
{
int len=lstr[j].length();
if(len<=l-i && lstr[j][0]==wstr[i])
{
int curw=i,curl=0;
while(curw<l)
{
if(lstr[j][curl]==wstr[curw++])
curl++;
if(curl==len)
{
dp[i]=min(dp[i],dp[curw]+curw-i-len);
//printf("[Changed]dp[%d]=%d.\n",i,dp[i]);
break;
}
}
}
}
}
cout<<dp[0]<<endl;
}
return 0;
}