每日一题(18): poj1159

本文介绍了一种通过求解最长公共子序列问题来解决字符串编辑距离的方法,并详细展示了如何从二维动态规划优化到一维,以减少内存使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 自己思考思路的时候开始觉得用动态规划,但是想不出公式。后来觉得如果把输入的字符串反过来,然后和原来的字符串相比求最大序列,然后答案就是原来的序列减去最大序列了。因为无法匹配的肯定需要添加。可以匹配的话就一定会出现在最大序列里面。这可以用反证法证明。解决了方法的问题。下面就是代码。其实就是一个最大序列匹配的问题。也是动态规划,公式:dp[i][j] = max{dp[i][j-1],dp[i-1][j],dp[i-1][j-1]}

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std;
//变量和要用到的数据
const int maxn = 5005;
char s[maxn];
char s2[maxn];
//int dp[maxn][maxn];
int dp[maxn][maxn];
int n;
int big (int temp1, int temp2, int temp3)
{
int result = temp1;
if(result<temp2)
result = temp2;
if(result<temp3)
result=temp3;
return result;
}
int value(char a,char b)
{
if(a==b)
return 1;
return 0;
}
int main()
{
freopen("input.txt","r",stdin);
while(~scanf("%d",&n))
{
scanf("%s",s+1);
for(int i = 1; i<=n; i++)
for(int j = 1; j<=n; j++)
{
dp[i][j] = 0;
}
//想到了解法,那就是把字符串倒过来和原来的字符串比较,取最长公共子序列。然后再三个字符串一起比较。
for(int i = 1; i<=n; i++)
{
s2[n-i+1] = s[i];
}
for(int i = 1; i<=n; i++)
{
for(int j = 1; j<=n; j++)
{
dp[i][j] = big(dp[i-1][j-1]+value(s[i],s2[j]),dp[i][j-1],dp[i-1][j]);
}

}


cout << (n-dp[n][n])<<endl;
}
}


但是内存超时。所以,需要优化。

2. 优化空间,因为5000*5000确实比较大,所以就想到可以用一维。上面公式里面因为新的值只和相邻的三个值有关。新的公式是,dp[i] = max{dp[i],dp[i-1], dp[i-1][j-1]};这里可以发现,dp[i]是上次更新的值,dp[i-1]是刚刚更新的值。只有dp[i-1][j-1]无法表示。所以,就用一个值来记录一下就可以了。于是有了下面的代码:一次ac。

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std;
//变量和要用到的数据
const int maxn = 5005;
char s[maxn];
char s2[maxn];
//int dp[maxn][maxn];
int dp[maxn];
int n;
//求三者之间的最大值
int big (int temp1, int temp2, int temp3)
{
int result = temp1;
if(result<temp2)
result = temp2;
if(result<temp3)
result=temp3;
return result;
}
//对比两个字符
int value(char a,char b)
{
if(a==b)
return 1;
return 0;
}
int main()
{
//freopen("input.txt","r",stdin);
while(~scanf("%d",&n))
{
//输入和初始化
scanf("%s",s+1);
for(int j = 0; j<maxn; j++)
{
dp[j] = 0;
}

//想到了解法,那就是把字符串倒过来和原来的字符串比较,取最长公共子序列。然后再三个字符串一起比较。
for(int i = 1; i<=n; i++)
{
s2[n-i+1] = s[i];
}
//最大公共字符串。不过在经典方法上改进了。因为不改进的话内存超了。因为实际纸盒上次的更新有关。所以可以优化到一维。但是和完全背包问题有
//有所不同的是,还需要对角的值,这个需要单独存储。就是下面的tempValue值。
int tempValue = 0;
for(int i = 1; i<=n; i++)
{
tempValue = 0;
for(int j = 1; j<=n; j++)
{
//if(s[i]==s2[j])
int tempValue2 = dp[j];
dp[j]  = big(tempValue+value(s[i],s2[j]), dp[j-1],dp[j]);
tempValue = tempValue2;
}
}
//输入结果
cout << (n-dp[n])<<endl;
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值