BZOJ 1633 [Usaco2007 Feb]The Cow Lexicon 牛的词典:dp【删字符最少】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1633
题意:
给你一个长度为n的主串a,和一个有m个字符串s[i]的单词书(s[i].size <= 25)。
问你至少删去多少个a中的字符,才能使a成为一个由s[i]组成的排列。
题解:
从后往前推。
表示状态:
dp[i] = min eliminations
表示第i个及以后的字符合法时,删去字符的最小数量。
找出答案:
ans = dp[0]
整个串合法。
如何转移:
对于第i个字符,要么删去(情况1),要么不删(情况2)。
(1)dp[i] = min dp[i+1] + 1
(2)dp[i] = min dp[i+t+len] + t
枚举s[i],长度为len。若i为s[i]的首字母,则至少要删去t个字符。
s[i]尾字母的下一位 = i+t+len。
所以dp[i]由dp[i+t+len]转移而来。
暴力求t就好,单次复杂度O(n)。程序总复杂度为O(n^2 * m)。
边界条件:
dp[n] = 0
AC Code:
1 // state expression: 2 // dp[i] = min eliminations 3 // i: considering ith letter 4 // 5 // find the answer: 6 // ans = dp[0] 7 // 8 // transferring: 9 // dp[i] = min dp[i+t+len] + t 10 // dp[i] = min dp[i+1] + 1 11 // 12 // boundary: 13 // dp[n] = 0 14 #include <iostream> 15 #include <stdio.h> 16 #include <string.h> 17 #define MAX_N 305 18 #define MAX_M 605 19 20 using namespace std; 21 22 int n,m; 23 int dp[MAX_N]; 24 string a; 25 string s[MAX_M]; 26 27 void read() 28 { 29 cin>>m>>n>>a; 30 for(int i=0;i<m;i++) 31 { 32 cin>>s[i]; 33 } 34 } 35 36 int cal_elim(int x,int y) 37 { 38 int cnt=0; 39 int pos=0; 40 for(int i=x;i<n;i++) 41 { 42 if(a[i]==s[y][pos]) pos++; 43 else cnt++; 44 if(pos==s[y].size()) return cnt; 45 } 46 return -1; 47 } 48 49 void solve() 50 { 51 dp[n]=0; 52 for(int i=n-1;i>=0;i--) 53 { 54 dp[i]=dp[i+1]+1; 55 for(int j=0;j<m;j++) 56 { 57 int t=cal_elim(i,j); 58 if(t!=-1) dp[i]=min(dp[i],dp[i+t+s[j].size()]+t); 59 } 60 } 61 } 62 63 void print() 64 { 65 cout<<dp[0]<<endl; 66 } 67 68 int main() 69 { 70 read(); 71 solve(); 72 print(); 73 }