常见动态规划(DP)

1最大子数组和

输入一个整形数组,数组里有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。要求时间复杂度为O(n)。

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
void DP(int a[], int n) {
	int dp[100];
	int i, j, maxVal = INT_MIN;
	memset(dp, 0 , sizeof(dp));
	for(i = 1; i <= n ;i ++) {
		dp[i]=max(dp[i-1]+a[i], a[i]);
		if(maxVal < dp[i])
			maxVal = dp[i];
	}
	cout<<maxVal<<endl;
}
int main() {
	int n, a[100];
	cin>>n;
	for(int i = 1; i<=n; i++) {
		cin >>a[i];	
	}
	DP(a,n);
	system("pause");
}


2 求最长的不上升子序列长度
设dp[i]表示前i个数的最长不上升序列的长度。
则,dp[i]=max{dp[j]+1},其中j<i and a[j]>=a[i]
这里0<j<i<=n。

#include <iostream>
#include <cstdio>
using namespace std;

void DP(int a[], int begin, int end) {
	int i, j, maxVal, dp[100];
	memset(dp, 0 , sizeof(dp));
	for(i = begin;i <=end; i++) {
		maxVal = INT_MIN;
		dp[i] = 1;
		for(j=begin; j <i;j++) {
			if(a[i]<= a[j])
				if(dp[j] > maxVal)
					maxVal = dp[j];
				dp[i] = maxVal +1;
		}
	}
	//for(i= begin; i<=end;i++)
	//	cout<<dp[i]<<"  ";
	//cout<<endl;
	cout<<dp[end]<<endl;
}
int main() {
	int n, i;
	int a[100];
	cin>>n;
	for(i =1; i<= n;i++)
		cin>>a[i];
	DP(a,1,n);
	system("pause");
}

3.最长回文子序列

并不是指子串。比如CCCAC   最长回文子 序列为 CCCC  而不是CCC

从二维数组dp右下角开始构造。 加入a[i]=a[j];那么问题就转为他的子串  ,即dp[i][j] = dp[i+1][j-1]+2

void DP(char a[], int begin, int end) {
	int dp[100][100];
	int i,j;
	memset(dp, 0 ,sizeof(dp));
	for(j = end;j >=begin ;j--) dp[j][j] =1;
	for(i = end-1;i >=begin ;i--){
		for(j = i+1; j <=end; j++) {
			if(a[i] == a[j])
				dp[i][j] = dp[i+1][j-1] +2;
			else
				dp[i][j] = dp[i][j-1];
		}
	}
	for(i=begin;i<=end;i++){
		for(j=begin;j<=end;j++)
			cout<<dp[i][j]<<" ";
		cout<<endl;
	}
	cout<<endl;
	cout<<dp[begin][end]<<endl;
}
int main() {
	int n, i;
	char a[100];
	cin>>n;
	for(i =1; i<= n;i++)
		cin>>a[i];
	DP(a,1,n);
	system("pause");
}

在一个数组中,检测是否存和等于某个数的子序列

比如n个数 ,a1, a2,a3.....an; 存在一个子序列a1, ak ,am..  (k<m)之和等于常数K

01背包的变形,其实也就是看数组里的数是否能填满容量为K的背包


#include <iostream>
#include <cstdio>
using namespace std;

void DP(int a[], int begin, int end, int t) {
	int i,j;
	int dp[100][100];
	memset(dp,0,sizeof(dp));
	for(i= begin;i<=end;i++) {//前i物品
		for(j=1;j<=t;j++){		//背包容量
			if(j>=a[i])
				dp[i][j] = max(dp[i-1][j-a[i]]+a[i], dp[i-1][j]);
			else
				dp[i][j] = dp[i-1][j];
		}
	}
	//for(i=begin;i<=end;i++)
	//{
	//	for(j=1;j<=t;j++)
	//		cout<<dp[i][j]<<" ";
	//	cout<<endl;
	//}
	if(dp[end][t]==t)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
}
int main() {
	int n, i, t;
	int a[100];
	cin>>n>>t;
	for(i =1; i<= n;i++)
		cin>>a[i];
	DP(a,1,n,t);
	system("pause");
}

酒店建造:n个可选的地址位于一条直线上,他们距离起点的距离依次为m1,m2...mn

在每个选址上最多修一座酒店,在位置i修建带来的利润为pi;

两个酒店之间的距离至少间隔k里

void DP(int a[],int p[], int begin, int end, int k) {
	int dp[100];
	int i,j;
	int MAX = INT_MIN;
	memset(dp, 0, sizeof(dp));
	dp[1] = p[1];
	for(i= begin; i<=end; i++) {
		for(j=i-1; j>=begin; j--) { 
			if(a[i]-a[j] >= k){
				dp[i] = dp[j]+p[i];
				if(dp[i] > MAX)
					MAX=dp[i];
				break;
			}
		}
	}
	cout<<MAX<<endl;
}
int main() {
	int n, i, k;
	int a[100], p[100];
	cin>>n>>k;
	for(i =1; i<= n;i++)
		cin>>a[i]>>p[i];
	DP(a,p,1,n,k);
	system("pause");
}

凑硬币

给定数量无限的硬币面值分别为x1,x2,x3...xn;将价格v兑换成零钱,能否满足

void DP(int a[],int begin, int end, int k) {
	int dp[100][100];
	int n,v,j;
	memset(dp, 0, sizeof(dp));
	for(n=begin;n<=end;n++) {
		for(v=1;v<=k;v++){
			for(j=0;j*a[n]<=v;j++) {
				dp[n][v] = max(dp[n-1][v-j*a[n]]+j*a[n] ,dp[n-1][v-j*a[n]]);
			}
		}
	}
	//for(int i=begin;i<=end;i++){
	//	for(j=0;j<=k;j++)
	//	cout<<dp[i][j]<<" ";
	//	cout<<endl;
	//}
	//cout<<dp[end][k]<<endl;
	if(dp[end][k] == k)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
}

int main() {
	int n, i, k;
	int a[100], p[100];
	cin>>n>>k;
	for(i =1; i<= n;i++)
		cin>>a[i];
	DP(a,1,n,k);
	system("pause");
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值