算法第二、三章上机实践报告
算法第二章上机实践报告
两个有序序列的中位数(分治)
时间复杂度为log(n),首先基本思想因为两个数组已经排好,而且求中位数,所以比较两个数组的中间元素,要是相等,则因为都是中位数,这两个数一定挨在一起,则整体的中位数必定是这个数,所以直接返回这个数。具体看下图
所以基本思路就是这样。为了保证递归的时候两个子数组长度相等,对mid可以这样处理
mid1=(la+ua)/2;
mid2=(lb+ub+1)/2;
这样的意思是若出现一个偶数组一个奇数组,得到的中间位置一样。
因为保证两数组长度一样,会出现数组只有两个的情况,如果按上面的方法会出现
造成死循环。所以进行处理
mid1=(la+ua)/2;
mid2=(lb+ub)/2;
这样处理的都是0位置元素
递归终止条件
当两个数组都只有一个元素的时候,中位数肯定就是小的那一个。
经过上述两个元素数组的处理,会出现一种类型的情况,a数组有1个元素,b数组有2个元素,意味着a的元素大于b的第一个元素,按中位数的定义,比较b的第二个元素和a,小的那个就是中位数。同理a,b调换。
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int b[100005];
int binary(int la,int ua,int lb,int ub){
int mid1=(la+ua)/2,mid2=(lb+ub+1)/2;
if(la==ua&&lb!=ub){
if(a[la]>b[ub]){
return b[ub];
}
return a[la];
}
if(la!=ua&&lb==ub){
if(a[ua]<b[ub]){
return a[ua];
}
return b[ub];
}
if(la==ua&&lb==ub){
if(a[la]>b[lb]){
return b[lb];
}
return a[la];
}
else{
if(la+1==ua&&lb+1==ub){
mid1=(la+ua)/2;
mid2=(lb+ub)/2;
}
if(a[mid1]==b[mid2]){
return a[mid1];
}
if(a[mid1]<b[mid2]){
return binary(mid1,ua,lb,mid2);
}
if(a[mid1]>b[mid2]){
return binary(la,mid1,mid2,ub);
}
}
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
}
cout<<binary(0,n-1,0,n-1);
}
算法第三章上机实践报告
编辑距离问题
设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。 将字符串A变换为字符串B所用的最少字符操作数称为字符串A到 B的编辑距离,记为d(A,B)。 对于给定的字符串A和字符串B,计算其编辑距离 d(A,B)。
输入格式:
第一行是字符串A,文件的第二行是字符串B。
提示:字符串长度不超过2000个字符。
输出格式:
输出编辑距离d(A,B)
输入样例:
在这里给出一组输入。例如:
fxpimu
xwrs
输出样例:
在这里给出相应的输出。例如:
5
算法描述
与最大公共子序列一致,有两个字符串,不同的是只需要对a字符串进行操作,先创建一个n行m列的dp[i][j],表示a[1..i]变成b[1...j]的最小编辑距离
先考虑删除元素的情况:
观察到如果选择删除操作,a[1..i]变成b[1..j]就只与a[1..i-1]变成b[1..j]有关,即dp[i][j]=dp[i-1][j]+1
插入元素的情况:
观察到如果选择插入操作,a的最后一项与b[j]相等,即不用管b[j],a[1..i]变成b[1..j]就只与a[1..i]变成b[1...j-1]有关,即dp[i][j]=dp[i][j-1]+1
替换元素的情况:
如果选择替换操作,分为b[j]与a[i]是否相等的两种情况,如果b[j]==a[i],则不用做替换,那么dp[i][j]=dp[i-1][j-1]
,如果不相等,则dp[i][j]=dp[i-1][j-1]+1
。
因此从上述三种操作中选择最小的一个,便是最小编辑距离。
#include<bits/stdc++.h>
using namespace std;
int dp[2005][2005];
/*
dp[i][j],i表示a从1到i的子串,j表示b从1到j的子串,
dp[i][j]表示a子串变到b子串的最小编辑距离
*/
string a;
string b;
int main(){
cin>>a;
cin>>b;
int n=a.length();
int m=b.length();
/*i=0,表示要变的a字符串为空,需要一个一个插入,所以初始化
条件是如下*/
for(int j=0;j<=m;j++){
dp[0][j]=j;
}
/*j=0,表示b字符串为空,需要把a一个一个删除,所以初始化
条件是如下*/
for(int i=0;i<=n;i++){
dp[i][0]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int tmp=min(dp[i-1][j]+1,dp[i][j-1]+1);
if(a[i-1]==b[j-1]){
dp[i][j]=min(tmp,dp[i-1][j-1]);
}else{
dp[i][j]=min(tmp,dp[i-1][j-1]+1);
}
}
}
cout<<dp[n][m];
return 0;
}
注意初始化操作,不同于以往的一串零。另外,程序里字符串是从0开始计数,因此判断两个字符是否相等时减1。
至于回溯的步骤:
新建一个n行m列的二维数组记录上一步的操作。
时间复杂度和空间复杂度均为n^2。
关于这道题的递推方程,感觉还是要靠某些经验。另外还很难验证自己所想到的递推式的正确性
理解与体会
动态规划最难的是寻找最优子结构和找出递推方程。路漫漫其修远兮,吾将上下而求索