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

Leohh發表於2017-10-02

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

 

相關文章