【第六周】算法之动态规划(一)

例题一:数字三角形

题目描述:
在这里插入图片描述
解题思路:
在这里插入图片描述
这也是一个递归的问题,把每一步都按照最优的解法算,三角形用二维数组存储
解题思路:

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int n;
int MaxSum(int r,int j){
	if(r==n){
		return D[r][j];
	}
	int x=MaxSum(r+1,j);
	int y=MaxSum(r+1,j+1);
	return max(x,y)+D[r][j];
}
int main(void)
{
	int i;
	int j;
	cin>>n;
	for(i=1;i<=n;i++){//编号从1开始 
		for(j=1;j<=i;j++){
			cin>>D[i][j];
		}
	}
	cout<<MaxSum(1,1)<<endl;
}

优化1:
虽然递归可以把结果算出来,但是复杂度却很高,因为好多数值需要重复计算,大量的浪费了时间,所以我们需要优化一下,把每次的结果保存一下。

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int n;
int maxSum[MAX][MAX];
int MaxSum(int r,int j){
	if(maxSum[r][j]!=-1){
		return maxSum[r][j];
	}
	if(r==n){
		maxSum[r][j]=D[r][j];
	}
	else{
		int x=MaxSum(r+1,j);
		int y=MaxSum(r+1,j+1);
	    maxSum[r][j]=max(x,y)+D[r][j];		
	}
	return maxSum[r][j];
}
int main(void)
{
	int i;
	int j;
	cin>>n;
	for(i=1;i<=n;i++){//编号从1开始 
		for(j=1;j<=i;j++){
			maxSum[i][j]=-1;//把每个数组的值记录为-1,表明这个数值没有被计算过 
			cin>>D[i][j];
		}
	}
	cout<<MaxSum(1,1)<<endl;
}

优化2:递归转成递推
我们可以从下往上推,最后一行的数字到最后一行的最远距离就是它本身,知道了这个条件后我们就可以知道倒数第二行的每个数字到最后一行的最短距离,依次类推,我们就可以推到三角形的第一个数字了
在这里插入图片描述

#include<iostream>
#include<algorithm>
#define MAX 101
using namespace std;
int maxSum[MAX][MAX];
int D[MAX][MAX];
int n;
int main(void)
{
	int i;
	int j;
	cin>>n;
	for(i=1;i<=n;i++){
		for(j=1;j<=i;j++){
			cin>>D[i][j];
		} 
	}
	for(j=1;j<=n;j++){
		maxSum[n][j]=D[n][j];
	}
	for(i=n-1;i>=1;i--){
		for(j=1;j<=i;j++){
			maxSum[i][j]=max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j];
		}
	}
	cout<<maxSum[1][1]<<endl;
}

其实我们还可以优化,因为不需要这么多的空间,所以只需要长度为n的一维数组即可。

例题二:最长上升子序列

题目描述:
在这里插入图片描述
解题思路:
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstring>
#include<algorithm>
#define MAX 101
using namespace std;
const int MAXN =1010;
int a[MAXN];
int maxLen[MAXN];
int main(void)
{
  int N;
  cin>>N;
  for(int i=1;i<=N;i++){
  	cin>>a[i];
  	maxLen[i]=1;
  }	
  for(int i=2;i<=N;i++){
  	//从第二个数开始,每次求以第i个数为终点的最长上升子序列
	  for(int j=1;j<i;j++){
	  	if(a[i]>a[j]){
	  		maxLen[i]=max(maxLen[i],maxLen[j]+1);//每次只要最小的数,如果前面的a[j]+1比此时的a[i]小就没必要更新了 
		  }
	  } 
  }
  cout<<*max_element(maxLen+1,maxLen+N+1);
  return 0;
}

例题三:最长公共子序列

题目描述:
在这里插入图片描述
解题思路:
在这里插入图片描述

#include<iostream>
#include<cstring>
using namespace std;
char sz1[1000];
char sz2[1000];
int maxlen[1000][1000];
int main()
{
	while(cin>>sz1>>sz2){
		int length1=strlen(sz1);
		int length2=strlen(sz2);
		int nTmp;
		int i,j;
		for(i=0;i<=length1;i++){
			maxLen[i][0]=0;
		}
		for(j=0;j<=length2;j++){
			maxLen[0][j]=0;
		}
		for(i=1;i<=length1;i++){
			for(j=1;j<=length2;j++){
				if(sz1[i-1]==sz2[j-2]){
					maxLen[i][j]=maxLen[i-1][j-1]+1;
				}else{
					maxLen[i][j]=max(maxLen[i][j-1],maxLen[i-1][j]);
				}
			}
		}
		cout<<maxLen[length1][length2]<<endl;
		
		
	}
	return 0;
}

发布了89 篇原创文章 · 获赞 56 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44867340/article/details/105436161