題目連結: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 }