HDU 4271Find Black Hand(DP 编辑距离变种)

本文探讨了在环形母串中寻找与多个小串编辑距离最小的子串问题,提出了一种结合枚举和动态规划(DP)的算法。针对不同数据规模,算法采用不同的策略,对于小数据集使用枚举+DP,而大数据集直接应用DP。文章详细解释了编辑距离计算的DP过程,并展示了如何处理母串长度小于子串的特殊情况。

题意:

         给定串长<=100000的母串和n(n<=10)且长度<=10的小串,问哪一个小串在母串中通过增加删除修改一个字母的操作数(即编辑距离)最小变成母串中的substring。母串是一个环。

       求最小的编辑距离,和对应字典序最小的字串。 

 

分析:

       比较明显的DP,编辑距离的变种。破环,在最后加倍。

       因为数据特殊。对于小数据枚举+dp,大数据直接dp。【1】dp[i][j]裸的编辑距离

【2】f[i][j]表示母串中第i个位置,包含子串中到第j个位置时的距离。这里注意当母串长度小于子串时,比如aaa,aaaaa会出错。。。还不会怎么处理。

详见代码:

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<string.h>
  4 #include<string>
  5 #include<algorithm>
  6 #include<iostream>
  7 
  8 using namespace std;
  9 
 10 string str;
 11 int n;
 12 
 13 string seq[11];
 14 int ans[11];
 15 string tmp;
 16 int dp[21][11];
 17 
 18 int calc(string a,string b)//DP,编辑距离
 19 {
 20     int la = a.length();
 21     int lb = b.length();
 22     dp[0][0] = 0;
 23     for (int i=1;i<=la;i++)
 24         dp[i][0] = i;
 25     for (int j=1;j<=lb;j++)
 26         dp[0][j] = j;
 27     for (int i=1;i<=la;i++)
 28         for (int j=1;j<=lb;j++)
 29         {
 30             if (a[i-1] == b[j-1]){
 31                 dp[i][j] = dp[i-1][j-1];
 32             }else{
 33                 dp[i][j] = dp[i-1][j-1] + 1;
 34             }
 35             dp[i][j] = min(dp[i][j],dp[i-1][j] + 1);
 36             dp[i][j] = min(dp[i][j],dp[i][j-1] + 1);
 37         }
 38     int res = dp[1][lb];
 39     for (int i=1;i<=la;i++)
 40         if (dp[i][lb] < res)
 41             res = dp[i][lb];
 42     return res;
 43 }
 44 int solve(string b){//枚举+DP
 45     int m = b.length();
 46     int res = m;
 47 
 48     for (int s=0;s<n;s++)
 49     {
 50         tmp = "";
 51         int t = min(n,20);
 52         for (int i=0;i<t;i++)
 53         {
 54             tmp = tmp + str[i+s];
 55         }
 56         int ttt = calc(tmp,b);
 57         if (ttt < res)
 58             res = ttt;
 59     }
 60 
 61     return res;
 62 }
 63 
 64 int f[110010][14];
 65 
 66 int solll(string b){
 67     if (n < 100)
 68         return solve(b);//小数据暴力枚举+DP
 69 
 70    //这里无法才处理n < m的情况,所以这种数据暴力之。
 71     
 72     f[0][0] = 0;
 73     int m = b.length();
 74     for (int j=0;j<=m;j++)
 75         f[0][j] = j;
 76     int res = m;
 77     int nn = n + min(2*m,n);
 78     for (int i=1;i<=nn;i++)
 79     {
 80         for (int j=0;j<=m;j++)
 81             f[i][j] = j;//每次都作为一个新的起点匹配。
 82         for (int j=1;j<=m;j++)
 83         {
 84             if (str[i-1]==b[j-1]){
 85                 f[i][j] = min(f[i][j],f[i-1][j-1]);
 86             }else{
 87                 f[i][j] = min(f[i][j],f[i-1][j-1]+1);
 88             }
 89             f[i][j] = min(f[i][j],f[i-1][j] + 1);
 90             f[i][j] = min(f[i][j],f[i][j-1] + 1);
 91         }
 92         if (f[i][m] < res)
 93             res = f[i][m];
 94     }
 95   //  printf("   %d\n",f[1][m]);
 96     return res;
 97 }
 98 int main()
 99 {
100     /*
101     n = 6;
102     str = "aaabbb";
103     str = str + str;
104     string a = "aaabbb";
105     string b = "bob";
106     printf("%d\n",solve(b));
107     printf("%d\n",solll(b));
108 */
109     while (cin>>str){
110         n = str.length();
111         str = str + str;
112 
113         int nn;
114         scanf("%d",&nn);
115         for (int i=1;i<=nn;i++)
116         {
117             cin>>seq[i];
118             ans[i] = solll(seq[i]);
119         //    printf("%d\n",ans[i]);
120         }
121         for (int i=1;i<=nn;i++)
122         {
123 
124             //ans[i] = solve(seq[i]);
125         }
126 
127         string res = seq[1];
128         int lll = ans[1];
129         for (int i=2;i<=nn;i++){
130             if (ans[i] < lll){
131                 lll = ans[i];
132                 res = seq[i];
133             }else if (ans[i] == lll && seq[i] < res){
134                 res = seq[i];
135             }
136         }
137         cout<<res<<" "<<lll<<endl;
138     }
139     return 0;
140 }
hdu4271(DP)

 

转载于:https://www.cnblogs.com/wangsouc/articles/3269684.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值