常见动态规划(DP)

来源:互联网 发布:器械健身计划软件 编辑:程序博客网 时间:2024/05/16 19:40

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;elsedp[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]);elsedp[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;elsecout<<"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;elsecout<<"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");}