UVALive 3608 Period(DP+二分)

13 篇文章 0 订阅

题目链接:点击打开链接

首先考虑这个问题与一般编辑问题的区别,在这个问题中可以在第二个串的任意地方掐掉重新对第一个串进行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 10000000
using 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 10000000
using 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);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值