题意:给一个字符串,和一些单词,问最少去掉几个字母才能使文章都由那些单词组成。
思路:用动态规划来解决,去掉的字母等于总的长度减去匹配好的字母数。
因为匹配数比较好理解,所以用匹配数来解决的问题。
f( i )表示到第i个位置为止的最大匹配数,因为位置增加1的时候最多增加一个匹配的单词,
所以每次只检查一下每个位置匹配每个单词能给给匹配数带来的增量,
每次找到匹配字母增加数最大的就是这个位置为止的最优解。
动态规划式:
当该单词无法匹配的话:f( i ) = f(i - 1)
如果可以匹配的话f( i ) = max(f( t ) + 该单词的长度,f(i - 1))
(t表示字符串里对应匹配对应单词的前一个位置)
这道题特别应该注意的是字符串匹配的时候,一定要注意检查指针的移动。
刚开始就是因为指针移动的地方马虎贡献了一次WA。
#include<iostream>
#include<Cstdio>
#include<string>
using namespace std;
int dp[1000], length, size, i, j, k;
char word[1000];
char dic[800][30];
int dicLength[800];
int match(int pos, int num)
{
int temp2 = pos, i, length1;
char t1 = word[pos], t2 = dic[num][dicLength[num] - 1];
if(t1 != t2)
return -1;
for(i = dicLength[num] - 1; i >= 0; i--)
{
t2 = dic[num][i];
while(temp2 >= 0 && word[temp2] != t2)
{
if(word[temp2] == t2)
break;
temp2--;
}
if(temp2 == -1)
return -1;
if(i != 0)
temp2--;
}
return temp2;
}
int main()
{
char *p; int max, temp, temp1;
scanf("%d%d", &size, &length);
scanf("%s", word);
p = word;
for(i = 0; i < size; i++)
{
scanf("%s", dic[i]);
p = dic[i]; dicLength[i] = 0;
while(*p != '\0')
{
p++;
dicLength[i]++;
}
}
dp[0] = 0;
for(i = 1; i < length; i++)
{
max = dp[i - 1];
for(j =0; j < size; j++)
{
temp = match(i, j);
if(temp > -1)
{
//cout << temp << endl;
if(temp == 0 && dicLength[j] > max)
max = dicLength[j];
else if(dicLength[j] + dp[temp - 1] > max)
max = dicLength[j] + dp[temp - 1];
}
}
dp[i] = max;
}
cout << length - dp[length - 1] << endl;
return 0;
}