1. 程式人生 > >BZOJ 1633 [Usaco2007 Feb]The Cow Lexicon 牛的詞典:dp【刪字符最少】

BZOJ 1633 [Usaco2007 Feb]The Cow Lexicon 牛的詞典:dp【刪字符最少】

小數 暴力 using 復雜 letter www 主串 blog 詞典

題目鏈接: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 }

BZOJ 1633 [Usaco2007 Feb]The Cow Lexicon 牛的詞典:dp【刪字符最少】