合工大程序设计艺术方法实验四动态规划Word格式.docx
- 文档编号:21787157
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:14
- 大小:45.05KB
合工大程序设计艺术方法实验四动态规划Word格式.docx
《合工大程序设计艺术方法实验四动态规划Word格式.docx》由会员分享,可在线阅读,更多相关《合工大程序设计艺术方法实验四动态规划Word格式.docx(14页珍藏版)》请在冰豆网上搜索。
思考:
输出变换的步骤。
(3)输入一个矩阵,计算所有的子矩阵中和的最大值。
例如,输入
0-2-70
92-62
-41-41
-180-2
输出为:
15
四、实验结果与分析(源程序及相关说明)
1.求两个字符串的最长公共子序列
算法思想:
通过动态规划求解:
seat二维数组用于表示选择的最长公共子序列以及输出时选择的方向,其中0表示可选的子序列点,1表示递归选择str1(0,i-1),str2(0,j)的公共子序列,-1选择str1(0,i),str2(0,j-1)的公共子序列,Long表示选择str1(0,i),str2(0,j)的公共子序列的长度,其中当递归结束时,Long[m][n]就存储着最大的长度。
先将Long数组第一行第一列初始化为0,方便计算,接着如果str[i]==str[j],则seat[i][j]为可选点,seat[i][j]=0,同时Long[i][j]=Long[i-1][j-1]+1,如果str[i]!
=str[j],则Long[i][j]=max(Long[i-1][j]Long[i][j-1]),如果选择前者seat[i][j]=1,否则seat[i][j]=-1;
当循环遍历了两个字符串后,就得出结论,在根据seat中存储的元素值,从m,n开始(m,n分别为两字符串的长度),先递归,后输出对应位置在字符串中的字符,递归结束,就可以输出字符串。
#include"
stdafx.h"
#include<
stdio.h>
string>
iostream>
usingnamespacestd;
#defineMAXLEN100
intseat[MAXLEN][MAXLEN];
//其中0表示可选的子序列点,1表示选择str1(0,i-1),str2(0,j)的公共子序列,-1选择str1(0,i),str2(0,j-1)的公共子序列
intLong[MAXLEN][MAXLEN];
//表示选择str1(0,i),str2(0,j)的公共子序列的长度
voidLCSLength(stringstr1,stringstr2,intm,intn)
{
inti,j;
for(i=0;
i<
=m;
i++)
Long[i][0]=0;
for(j=1;
j<
=n;
j++)
Long[0][j]=0;
//第一行第一列不使用,方便计算
for(i=1;
{
for(j=1;
{
if(str1[i-1]==str2[j-1])
{
Long[i][j]=Long[i-1][j-1]+1;
seat[i][j]=0;
}
elseif(Long[i-1][j]>
=Long[i][j-1])
Long[i][j]=Long[i-1][j];
seat[i][j]=1;
else
Long[i][j]=Long[i][j-1];
seat[i][j]=-1;
}
}
}
//以str1为标准输出
boolPrint(stringstr1,inti,intj,int&
m,int&
n)
if(i==0||j==0)
returntrue;
if(seat[i][j]==0)
//先依次递归之后子序列,之后再输入该子序列符号,以保证输入的正确性
Print(str1,i-1,j-1,m,n);
m=i;
n=j;
cout<
<
str1[i-1];
elseif(seat[i][j]==1)
Print(str1,i-1,j,m,n);
else
Print(str1,i,j-1,m,n);
voidLCS()
stringstr1,str2;
intm=0,n=0,i=0,j=0;
cout<
"
输入第一个字符串:
"
<
endl;
cin>
>
str1;
输入第二个字符串:
str2;
i=str1.length();
j=str2.length();
LCSLength(str1,str2,i,j);
最长子序列为:
Print(str1,i,j,m,n);
最长子序列长度为:
Long[m][n]<
;
system("
pause"
);
int_tmain(intargc,_TCHAR*argv[])
LCS();
return0;
2.字符串的变换:
使用动态规划的思想:
定义两个数组,Distance表示距离,handle表示操作,其中handle存储的数1为删除,2为插入,3为替换,4为相同跳到下一个字符,5为结束状态。
先初始化,令handle开始的第一行第一列为5,如果str1[i]!
=str2[0],handle为3,列同理;
其中Distance为对应的行号或者列号。
两重for循环遍历所有组合的点,如果str1[i]==str2[j],则Distance[i][j]=Distance[i-1][j-1],handle[i][j]=4;
否则handle[i][j]=minval(Distance[i-1][j]+1,Distance[i][j-1]+1,Distance[i-1][j-1]+1,Distance[i][j]);
minval函数的作用是比较最大值,并返回最大值对应的操作,1为删除,2为插入,3为替换,当循环结束时,在Distance[m-1][n-1](m,n分别为两字符串的长度)中存储着最少操作次数
输出步骤:
最后先递归,后操作,修改str1字符串,表示操作的步骤。
#include<
vector>
#defineMAX1000
intDistance[MAX][MAX];
inthandle[MAX][MAX];
conststringOPERATOR_NAME[4]={
删除串a中的一个字符:
在串a插入一个元素:
将串a中的"
字母换为另一个字母:
};
//比较最大值,并返回最大值对应的操作,1为删除,2为插入,3为替换
intminval(intx,inty,intz,int&
d)
if(x<
y)
if(x<
z)
d=x;
return1;
else
d=z;
return3;
if(y<
d=y;
return2;
voidPrintHandle(inti,intj,string&
str1,stringstr2)
if(handle[i][j]==1)//删除
OPERATOR_NAME[0]<
str1[i]<
str1.erase(str1.begin()+i);
当前a字符串:
str1<
PrintHandle(i-1,j,str1,str2);
elseif(handle[i][j]==2)//插入
OPERATOR_NAME[1]<
str2[j]<
str1.insert(str1.begin()+i+1,str2[j]);
PrintHandle(i,j-1,str1,str2);
elseif(handle[i][j]==3)//替换
OPERATOR_NAME[2]<
OPERATOR_NAME[3]<
str1.insert(str1.begin()+i,str2[j]);
PrintHandle(i-1,j-1,str1,str2);
elseif(handle[i][j]==4)
elseif(handle[i][j]==5)
system("
if(str1.length()>
str2.length())
if(str1[i-1]!
=str2[j])
cout<
str1[i-1]<
str1.erase(str1.begin()+i-1);
if(i>
0)
PrintHandle(i-1,j,str1,str2);
if(str1[i]!
=str2[j-1])
str2[j-1]<
str1.insert(str1.begin()+i,str2[j-1]);
if(j>
PrintHandle(i,j-1,str1,str2);
//编辑距离函数,str1str2为操作的字符串
voidOUTdistance(stringstr1,stringstr2,intlenthofstr1,intlenthofstr2)
i<
lenthofstr1;
i++){
if(str1[i]==str2[0])
Distance[i][0]=i;
handle[i][0]=5;
Distance[i][0]=i+1;
handle[i][0]=3;
lenthofstr2;
if(str1[0]==str2[i])
Distance[0][i]=i;
handle[0][i]=5;
Distance[0][i]=i+1;
handle[0][i]=3;
j<
//如果对应的字符相等,原问题交给子问题处理,即不用任何操作
if(str1[i]==str2[j])
Distance[i][j]=Distance[i-1][j-1];
handle[i][j]=4;
//否则的话,对左、右、左上角的值进行求最小值
handle[i][j]=minval(Distance[i-1][j]+1,Distance[i][j-1]+1,Distance[i-1][j-1]+1,Distance[i][j]);
PrintHandle(lenthofstr1-1,lenthofstr2-1,str1,str2);
最少的操作次数是:
Distance[lenthofstr1-1][lenthofstr2-1]<
intSTRChang(){
intlenthofstr1=str1.length();
intlenthofstr2=str2.length();
OUTdistance(str1,str2,lenthofstr1,lenthofstr2);
STRChang();
3.计算所有的子矩阵中和的最大值
使用动态规划:
使用一个二维数组,其中num[i][j]存储矩阵i*j的元素和。
num存储的方法是:
num[i][j]+=num[i-1][j];
循环输入后就得到了矩阵元素和的二维数组。
使用三个变量i,j,k来遍历,一个矩阵大小是M*N的,那么使i从0到M,再使j从每一个i到M,遍历所有行可能。
再考虑列方向,直接在每一种i,j组合下,进行0到N的遍历,那么这样就等于是把所有子矩阵的情形给遍历完了。
每次遍历的过程是:
从i,j点开始,temp=num[j][k]-num[i-1][k],表示行为i-1到j,列为1到k的矩阵的值,nummax=max(nummax,0)+temp表示i-1到j,列为1到k的矩阵中从k向上最大的子矩阵元素和,Max=max(nummax,Max)表示最大的子矩阵和,当遍历结束,就可以求出最大举证和。
本算法可以求出100*100的矩阵
stdlib.h>
string.h>
time.h>
algorithm>
intnum[MAX][MAX];
voidsubMatrix()
intn;
intr,c;
inti,j,k;
srand(unsigned(time(0)));
请输入行列数:
r>
c;
memset(num,0,sizeof(num));
输入矩阵:
=r;
=c;
cin>
num[i][j];
num[i][j]+=num[i-1][j];
//num[i][j]表示i行j列矩阵的元素和
inttemp=0;
//记录一行的元素和
intMax=num[1][1];
intnummax;
//记录一个矩阵的元素和
for(j=i;
nummax=0;
for(k=1;
k<
k++)
temp=num[j][k]-num[i-1][k];
nummax=max(nummax,0)+temp;
Max=max(nummax,Max);
子矩阵中和的最大值为:
Max<
subMatrix();
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 合工大 程序设计 艺术 方法 实验 动态 规划