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 }

 

posted @ 2017-10-02 15:58  Leohh  阅读(216)  评论(0编辑  收藏  举报