动态规划Dynamic programming

有新发现了不?

最长上升子序列

传送门

#include <bits/stdc++.h>
using namespace std;
//1、分解成子问题 2、无后效性,一种状态A只与另一种状态B的值有关,与状态B的到达方式无关 


int main(int argc, char** argv) {
	int n;
	cin>>n;
	int a[n];
		int dp[n];//存放以a[k]为结尾的序列的最长上升子序列
//	dp[0]=1;
	for(int i=0;i<n;i++){
		cin>>a[i];
		dp[i]=1;
	}

	
	for(int k=1;k<n;k++){
		int m=1;//不能初始化为-1,如果dp[k]前面的数都比他大呢,那么 dp[k]就等于-1了呀 
		for(int i=0;i<k;i++){
			if(a[i]<a[k]){
				dp[k]=dp[i]+1;
				if(dp[k]>m)m=dp[k];
			}
		}
		dp[k]=m;
//	for(int i=0;i<k;i++){
//		if(a[i]<a[k])dp[k]=max(dp[i]+1,dp[k]);
//	}
	}
	cout<<*max_element(dp,dp+n);
//	int m=-1;
//	for(int k=0;k<n;k++){
//		if(dp[k]>m)m=dp[k];
//	}
//	cout<<m;
	return 0;
}

help Jimmy

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f   //超级适合表示infinite 
struct st{
	int x1,x2,h; 
}a[1001];
//st  a[1001];
bool cmp(st s1,st s2){
	return (s1.h<s2.h);
	//按照板子的高度由低到高 排序编号,地面编号为0,出发处编号为n+1 
}
int dp[1001][2]; //dp[i][0]表示 从第i块板子对应位置 往左而下 到达地面的最短时间
int n,x,y,mx;
void left(int i){//求出 从第i块板子对应位置 往左而下 到达地面的最短时间
	int k=i-1;//i左下角的一块板子、
	while(k>0&&a[i].h-a[k].h<=mx){
	if(a[k].x1<=a[i].x1&&a[k].x2>=a[i].x1) {
		dp[i][0]=a[i].h-a[k].h+min(dp[k][0]+a[i].x1-a[k].x1,dp[k][1]+a[k].x2-a[i].x1);
		return;
	}
	else k--;//再找左下方向下面一块板子 
}
	if(a[i].h-a[k].h>mx)dp[i][0]= inf;
	else if(k==0)dp[i][0]=a[i].h-a[k].h; 
}
void right(int i){//求出 从第i块板子对应位置 往右而下 到达地面的最短时间
	int k=i-1;//i右下角的一块板子、
	while(k>0&&a[i].h-a[k].h<=mx){
	if(a[k].x1<=a[i].x2&&a[k].x2>=a[i].x2) {
		dp[i][1]=a[i].h-a[k].h+min(dp[k][0]+a[i].x2-a[k].x1,dp[k][1]+a[k].x2-a[i].x2);
		return;
	}
	else k--;//再找左下方向下面一块板子 
}
	if(a[i].h-a[k].h>mx)dp[i][1]= inf;
	else if(k==0)dp[i][1]=a[i].h-a[k].h; 
}
int main(int argc, char** argv) {
	int t;
	cin>>t;
	while(t--){
		cin>>n>>x>>y>>mx;
//		int a[n][3];
//		for(int i=0;i<n;i++){
//			for(int j=0;j<3;j++){
//				cin>>a[i][j];
//			}
//		}
//以后要反应过来用结构体噢,三元组的形式,一来仅用a[i][0/1/2]不能很好见名知意
//二来 刚刚思索了一会怎么给这个三元组根据a[i][2]来排序,Cpp运算符重载和sort函数似乎都做不到 
//数据结构似乎讲过,不过当然想不起来
	for(int i=1;i<=n;i++){
		cin>>a[i].x1>>a[i].x2>>a[i].h;
	}
	a[n+1].h=y;
	a[n+1].x1=a[n+1].x2=x;
	a[0].h=0;
	a[0].x1=-20000 ;
	a[0].x2=20000;	
	sort(a,a+n+1,cmp);
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n+1;i++){
		left(i);
		right(i);
	}	
	cout<<min(dp[n+1][0],dp[n+1][1])<<endl; 
	}
		return 0;
	} 

滑雪

#include <bits/stdc++.h>
using namespace std; 
#define MAX 105
int a[MAX][MAX];
int dp[MAX][MAX];
int m,n;
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int dfs(int x,int y){
	if(dp[x][y]>0)return dp[x][y];//如果这个点的最长路径已经算出,直接返回
	dp[x][y]=1;
		for(int k=0;k<4;k++){
			if((x+dx[k])>=0&&(x+dx[k])<=m-1&&(y+dy[k])>=0&&(y+dy[k])<=n-1&&a[x+dx[k]][y+dy[k]]<a[x][y])
			dp[x][y]=max(dp[x][y],dfs(x+dx[k],y+dy[k])+1);
			}
			return dp[x][y];
}
int main(int argc, char** argv) {
	cin>>m>>n;
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			cin>>a[i][j];
			dp[m][n]=-1;
		}
	}	
	int ans=0;
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			ans=max(ans,dfs(i,j));//从哪个点出发路径最长 
		}
	}
	cout<<ans<<endl;	
		return 0;
	} 

#include<iostream>  
using namespace std;
const int Max = 105;
 
int row, col;
int map[Max][Max];                           //  记录图各点的高度。  
int dp[Max][Max];                            //  记录以各点为起点的最长下降路径的长度。  
 
int dfs(int r, int c)
{
	if (dp[r][c] != 0)
		return dp[r][c];      //  若dp[r][c]不为0,则表示它已被访问。  
	int max = 1;
	if (r + 1 <= row && map[r][c] > map[r + 1][c])
	{
		int len = dfs(r + 1, c) + 1;
		if (len > max)
			max = len;
	}
	if (r - 1 >= 1 && map[r][c] > map[r - 1][c])
	{
		int len = dfs(r - 1, c) + 1;
		if (len > max)
			max = len;
	}
	if (c + 1 <= col && map[r][c] > map[r][c + 1])
	{
		int len = dfs(r, c + 1) + 1;
		if (len > max)
			max = len;
	}
	if (c - 1 >= 1 && map[r][c] > map[r][c - 1])
	{
		int len = dfs(r, c - 1) + 1;
		if (len > max)
			max = len;
	}
	return map[r][c] = max;
}
 
int main()
{
	int i, j;
	cin >> row >> col;
	for (i = 1; i <= row; i++)
	for (j = 1; j <= col; j++)
		cin >> map[i][j];
	int ans = 0;
	memset(dp, 0, sizeof(dp));//给dp[][]全部初始化为0
	for (i = 1; i <= row; i++)
	for (j = 1; j <= col; j++)
	{
		dp[i][j] = dfs(i, j);  //  用记忆化搜索求出dp[i][j],同时也求出了其路径上的dp[x][y]。  
		if (dp[i][j] > ans)
			ans = dp[i][j];
	}
	cout << ans << endl;
	return 0;
}
//这种做法也差不多,没用dx,dy方向数组罢了
原文链接:https://blog.csdn.net/qq_42020563/article/details/80644017

神奇口袋

#include <bits/stdc++.h>
using namespace std;
int dp[25][45]; //dp[i][j]表示从i件商品选出总质量j的选法 
int main(int argc, char** argv) {
		int n;
		cin>>n;
		int w[n];
		for(int i=0;i<n;i++){
			cin>>w[i];
		}
		memset(dp,0,sizeof(dp));
		for(int j=0;j<=n;j++){
			dp[j][0]=1;//选的质量为0,一种选法:啥也不选 
		}
		for(int i=1;i<=n;i++){//从i件商品中选,选不选第i件商品 对应的是 w[i-1]
			for(int j=1;j<=40;j++){
			if(j-w[i-1]>=0)dp[i][j]=dp[i-1][j]+dp[i-1][j-w[i-1]];
			else dp[i][j]=dp[i-1][j];
			}
		}
		cout<<dp[n][40]<<endl;
		return 0;
	} 

7113:Charm Bracelet(典型01口袋)

#include <bits/stdc++.h>
using namespace std; 
#define MAX 34050
int v[MAX];//每件物品的重量 
int w[MAX];//每件物品的价值 
int n,m;
int dp[MAX]; 
int main(int argc, char** argv) {
		cin>>n>>m;//n个物品,拿走至多m重量
		 for(int i=0;i<n;i++){
		 	cin>>w[i]>>v[i];
		 } 
		 memset(dp,0,sizeof(dp));
		 for(int i=1;i<=n;i++){
		 	for(int j=m;j>=1;j--){//递推出dp[i][j]
		 		if(j>=w[i-1])dp[j]=max(dp[j],v[i-1]+dp[j-w[i-1]]);
			 }
		 } 
		 cout<<dp[m];
		return 0;
	} 

7215:简单的整数划分问题

#include <bits/stdc++.h>
using namespace std;
#define MAX 51 
int dp[MAX][MAX];//递推思想:dp[i][j]表示整数i以j为最大因子的划分种数 
int main(int argc, char** argv) {
	int x;
	memset(dp,0,sizeof(dp));
		while(cin>>x){
	//	5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
	//从221,可以看出,以2为最大因子那么划分x-2的因子不能超过2 
	//dp[i][j]=dp[i-j][j]+dp[i][j-1]; i>=0
		dp[0][0]=1;//考虑到分解x,只有下本身这个因子这种分解方式 
		for(int i=0;i<=x;i++){
			for(int j=1;j<=x;j++){
				if(i<j)dp[i][j]=dp[i][j-1]; 
				else dp[i][j]=dp[i-j][j]+dp[i][j-1];
			}
		}
	
		cout<<dp[x][x]<<endl;//x以x为最大因子,划分方式中因子可以不含x,但是一定都小于x 
}
		return 0;
	}

7219:复杂的整数划分问题

#include <bits/stdc++.h>
using namespace std;
#define MAX 51 
typedef long long int ll;
ll dp[MAX][MAX];//dp[i][j]表示把i划分成j个数的划分种数 
ll dp2[MAX][MAX];//dp2[i][j]表示把i划分成若干个不同整数的划分种数 ,以j为最大因子 
ll dp3[MAX][MAX];//dp2[i][j]表示把i划分成
int main(int argc, char** argv) {
	int n,k;
	while(cin>>n>>k){
	memset(dp,0,sizeof(dp));//dp[5][2]
//		for(int i=1;i<=n;i++)dp[i][1]=1;
	for(int i=1;i<=n;i++){
		dp[i][1]=1;
	for(int j=2;j<=n;j++){
		if(i>=j){
//		dp[i][j]+=dp[i-1][j-1];
//		if(i-j>=0)dp[i][j]+=dp[i-j][j];
		dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
		}
}
}
	cout<<dp[n][k]<<endl;	
	memset(dp2,0,sizeof(dp2));//dp[5][2]
		dp2[0][0]=1;//唯独这个特殊,当划分组合中只有最大因子这一个因子 
	for(int i=0;i<=n;i++){
		for(int j=1;j<=n;j++){//至少以1为最大因子咯,以0就是没有分解方式 已经初始化为0啦 
		if(i<j)dp2[i][j]=dp2[i][i]; 
		else{	
		dp2[i][j]=dp2[i-j][j-1]+dp2[i][j-1];//5 5
			}			
		}
	} 
	cout<<dp2[n][n]<<endl;
	
		memset(dp3,0,sizeof(dp3));//dp[5][2]
		dp3[0][0]=1;
//		for(int j=0;j<=n;j++){//这是我没想到的 没想明白 
//			dp3[j][1]=1;
//			if(j%2==1)dp3[0][j]=1;//只由自身一个奇数组成时,i得到0,
至于为何j要为奇数因为 ,得到这个0是由上一个i减去这个j的,i==j必须要是一个奇数 
//		}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){//至少以1为最大因子咯,以0就是没有分解方式 已经初始化为0啦 
			if(j%2==1){
//			if(i>=j)dp3[i][j]=dp3[i-j][j]+dp3[i][j-1];
				if(i>j)dp3[i][j]=dp3[i-j][j]+dp3[i][j-1]; 
				else if(i==j)dp3[i][j]=dp3[i][j-1]+1;
				else dp3[i][j]=dp3[i][i];
			}
//			if(i>=j){//dp3[i][j]=dp3[i-j][j-2]+dp3[i][j-2];//5 5
//		}
			else dp3[i][j]=dp3[i][j-1];
		}
	} 
	cout<<dp3[n][n]<<endl;
//	if(n%2==1)cout<<dp3[n][n]<<endl;
//	else cout<<dp3[n][n-1]<<endl;//其实没有必要,上面一条else语句就会将偶数转化成奇数的 
}
		return 0;
	} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值