HNU_算法_实验3(2021级)-算法实验1-字符串比较问题

一、实验名称

实现题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()
  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值