一、实验名称
实现题3-17 字符串比较问题:
问题描述:
对于长度相同的2个字符串A和B,其距离定义为相应位置字符距离之和。2个非空格字符的距离是它们的ASCII码之差的绝对值。空格与空格的距离为0;空格与其它字符的距离为一定值k。
在一般情况下,字符串A和B的长度不一定相同。字符串A的扩展是在A中插入若干空格字符所产生的字符串。在字符串A 和B 的所有长度相同的扩展中,有一对距离最小的扩展,该距离称为字符串A和B的扩展距离。
对于给定的字符串A和B,试设计一个算法,计算其扩展距离。对于给定的字符串A和B,编程计算其扩展距离。
二、实验目的
通过上机实验,要求掌握字符串比较问题的问题描述、算法设计思想、程序设计。
三、实验原理
解决字符串比较问题,并计算出程序运行所需要的时间
四、实验步骤
d(i,j)来描述A[1:i]和B[1:j]两字符串之间的扩展距离:
可以证明d[i,j]具有最优子结构的性质,满足如下状态转移方程:
d(i,j)=min{d(i-1,j)+k,d(i,j-1)+k,d(i-1,j-1)+dis(ai,bi)}
预处理:
首先对dp数组进行预处理,到当i=0时,B[j]之前的字母匹配的空格,所以dp[0][j]预处理为kj,
对应的j=0时dp[i][0]预处理为ki,
而dp[0][0]预处理为0:
对于题目中给出的例子cmc snmn 2,则有:
0 | s | n | m | n | |
0 | 0 | 2 | 4 | 6 | 8 |
c | 2 | ||||
m | 4 | ||||
c | 6 |
递推:
从1开始按照递推式进行递推:
五、关键代码
1.动态规划求解
int dpComp(int k,string A,string B)
{
int len1=A.length(),len2=B.length();
vector<vector<int> >dp(len1+1,vector<int>(len2+1));
for(int i=1;i<=len1;i++)//预处理
{
dp[i][0]=k*i;
}
for(int i=1;i<=len2;i++)//预处理
{
dp[0][i]=k*i;
}
dp[0][0]=0;
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
dp[i][j]=mins(dp[i-1][j]+k,dp[i][j-1]+k,dp[i-1][j-1]+abs(A[i-1]-B[j-1]));
}
}
return dp[len1][len2];
}
2.自己生成测试数据
//生成规模为n的随机数
cout<<"请输入数据规模n:"<<endl;
int n,c;
cin>>n;
ofstream out("input1.txt");
srand((unsigned)time(NULL));
/*
ASCII码的可见字符包括数字、字母、标点符号和一些特殊字符。
其中,0-31是控制字符,32是空格,33-126是可打印字符,127是DEL(删除)字符。
*/
//字符串A长度为n,都为可打印字符
for(int i=0;i<n;i++){
out<<static_cast<char>(' ' + std::rand() % (126 - ' ' + 1));
}
out<<endl;
//[a,b]
int a=0,b=n;
int Bl=(rand() % (b-a))+ a + 1;
//字符串B长度为Bl,范围是[a,b],都为可打印字符
for(int i=0;i<Bl;i++){
out<<static_cast<char>(' ' + std::rand() % (126 - ' ' + 1));
}
out<<endl;
//k,不妨设k的值在0-100之间
a=0,b=100;
out<<(rand() % (b-a))+ a + 1<<"\n";
out.close();
六、测试结果
时间复杂度:O(len1*len2)
n从100-10000,每次递增100的测试结果:
自定义输入n的数值的测试结果:
七、实验心得
通过这次实验,我了解熟悉了字符串比较问题的求解过程及原理。对于自己实现的案例,感觉存在误差,画出来的图不符合直觉,也可能是求解运行时间的程序有问题。
八、完整代码
#include <iostream>
#include <fstream>
#include <windows.h>
#include <time.h>
#include <cmath>
#include <vector>
using namespace std;
// 定义一个宏,用于获取三个数的最小值
#define mins(a,b,c) min(min(a,b),c)
int dpComp(int k,string A,string B)
{
int len1=A.length(),len2=B.length();
vector<vector<int> >dp(len1+1,vector<int>(len2+1));
for(int i=1;i<=len1;i++)//预处理
{
dp[i][0]=k*i;
}
for(int i=1;i<=len2;i++)//预处理
{
dp[0][i]=k*i;
}
dp[0][0]=0;
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
dp[i][j]=mins(dp[i-1][j]+k,dp[i][j-1]+k,dp[i-1][j-1]+abs(A[i-1]-B[j-1]));
}
}
return dp[len1][len2];
}
int main(int argc, char** argv) {
ofstream out1("output.txt");
int x=1;
while(1){
//生成规模为n的随机数
cout<<"请输入数据规模n:"<<endl;
int n,c;
cin>>n;
ofstream out("input1.txt");
srand((unsigned)time(NULL));
/*
ASCII码的可见字符包括数字、字母、标点符号和一些特殊字符。
其中,0-31是控制字符,32是空格,33-126是可打印字符,127是DEL(删除)字符。
*/
//字符串A长度为n,都为可打印字符
for(int i=0;i<n;i++){
out<<static_cast<char>(' ' + std::rand() % (126 - ' ' + 1));
}
out<<endl;
//[a,b]
int a=0,b=n;
int Bl=(rand() % (b-a))+ a + 1;
//字符串B长度为Bl,范围是[a,b],都为可打印字符
for(int i=0;i<Bl;i++){
out<<static_cast<char>(' ' + std::rand() % (126 - ' ' + 1));
}
out<<endl;
//k,不妨设k的值在0-100之间
a=0,b=100;
out<<(rand() % (b-a))+ a + 1<<"\n";
out.close();
int i,maxi,mini;
LARGE_INTEGER nFreq,nBegin,nEnd;
double time;
ifstream in("input1.txt");
string A,B;
//in>>A;
getline(in,A);
n=A.length();
//in>>B;
getline(in,B);
Bl=B.length();
if(n<1000){
cout<<"字符串A: "<<n<<"\t"<<A<<endl;
cout<<"字符串B: "<<Bl<<"\t"<<B<<endl;
}
else{
cout<<"字符串A: "<<n<<endl;
cout<<"字符串B: "<<Bl<<endl;
}
int k;
in>>k;
cout<<"空格与其它字符的距离k: "<<k<<endl;
long long result;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBegin);
result=dpComp(k,A,B);
QueryPerformanceCounter(&nEnd);
time=(double)(nEnd.QuadPart-nBegin.QuadPart)/(double)nFreq.QuadPart;
cout<<"结果:"<<result<<"\n查询时间:"<<time<<endl<<endl;
out1<<n<<' '<<time<<endl;
in.close();
}
out1.close();
return 0;
}
九、绘图代码
import matplotlib.pyplot as plt
# 读取txt文件,假设文件名为data.txt
file_path = 'F:\\3-CourseMaterials\\3-1\\3-算法设计与分析\实验\lab3\\1-code\\3-字符串比较问题\\output.txt'
# 存储x和y的列表
x_values = []
y_values = []
# 读取文件并提取数据
with open(file_path, 'r') as file:
for line in file:
# 假设数据以空格或逗号分隔
x, y = map(float, line.strip().split())
x_values.append(x)
y_values.append(y)
print(x_values)
print(y_values)
# 绘制图形
plt.plot(x_values, y_values)
plt.title('X vs Y Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()