UVALive 3608 Period(DP+二分)

来源:互联网 发布:淘宝网在线客服 编辑:程序博客网 时间:2024/05/19 12:27

题目链接:点击打开链接

首先考虑这个问题与一般编辑问题的区别,在这个问题中可以在第二个串的任意地方掐掉重新对第一个串进行dp

也就是说,可以将dp[n][j]的状态转移给dp[0][j](n为第一个串的长度)

要求的答案是所有段中编辑距离最大的那段的最小值,也就是说需要记录所有从n转移到0的时候的dp[n][j]的值以用来比较取最大。

显然这么做十分麻烦,所以可以考虑设一个编辑距离上界,只有当不超过这个上界的情况下才可以进行从n到0的转移。

于是就可以省去dp[n][j]的记录而直接默认答案为该上界。

基于这个思想,我们可以二分这个上界来dp,从而找到上界的最小值。

自己写了一份代码,虽然能够AC,却过不了自己出的随机数据,不知道错在哪了,代码如下:

#include<bits/stdc++.h>#define INF 10000000using namespace std;char s1[55],s2[5005];int dp[55][5005];int n,m;bool check(int lmt){for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)dp[i][j]=INF;dp[0][0]=0;for(int j=0;j<=m;j++){bool flag=false;for(int i=0;i<=n;i++){int p=dp[i][j];if(i>0)dp[i][j]=min(dp[i][j],dp[i-1][j]+1);if(j>0)dp[i][j]=min(dp[i][j],dp[i][j-1]+1); if(i>0&&j>0){if(s1[i-1]==s2[j-1])dp[i][j]=min(dp[i][j],dp[i-1][j-1]);else dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1); }if(p!=dp[i][j])flag=true;}if(dp[n][j]<=lmt&&flag){dp[0][j]=0;j--;}}return dp[n][m]<=lmt;}int main(){//freopen("1.txt","r",stdin);//freopen("2.txt","w",stdout);int t;scanf("%d",&t);while(t--){scanf("%s%s",s1,s2);n=strlen(s1),m=strlen(s2);int l=0,r=n;while(r-l){int mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}printf("%d\n",l);}}
之后再参考了这个博客改了自己的代码,于是就能过自己出的数据了。但是并不知道为什么上面那个会错,代码如下:

#include<bits/stdc++.h>#define INF 10000000using namespace std;char s1[55],s2[5005];int dp[55][5005];int n,m;bool check(int lmt){for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)dp[i][j]=INF;dp[0][0]=0;for(int j=0;j<=m;j++){if(dp[n][j]<=lmt)dp[0][j]=0;for(int i=0;i<=n;i++){dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1);dp[i][j+1]=min(dp[i][j+1],dp[i][j]+1);if(i<n&&j<m){if(s1[i]==s2[j])dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]);else dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]+1);}}}return dp[n][m]<=lmt;}int main(){int t;scanf("%d",&t);while(t--){scanf("%s%s",s1,s2);n=strlen(s1),m=strlen(s2);int l=0,r=n;while(r-l){int mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}printf("%d\n",l);}}


0 0
原创粉丝点击