动态规划 | 1007 最大连续子序列和
本题是对“ 最大连续子序列和”这个问题的变形,只要读懂题,处理好细节,没有什么设坑的地方。
这道题可以用贪心和DP来做,我开始用贪心做的,wa了一个测试点。经过了一波冷静的分析,查出了原因,AC了。
贪心
贪心的思路很简单,遍历一遍数组,用mA记录最优解的第一个数,用mB记录最优解的第二个数,mSum记录最优解,a、b、sum都是临时变量。
一下加粗的代码是漏打的bug:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100000 #define MAX (1<<30)-1 #define V vector<int> using namespace std; int num[LEN]; int main(){ // freopen("1007.txt","r",stdin); int i,n,t,a,b,mSum=-1,sum=0,mA,mB; I("%d",&n); FF(i,n) I("%d",&num[i]); a=num[0]; FF(i,n){ t=num[i]; if(sum+t<0){ sum=0; a=num[i+1]; }else{ sum+=t; b=t; if(sum>mSum){ mSum=sum; mA=a; mB=b; } } } if(mSum<0){ O("%d %d %d",0,num[0],num[n-1]); }else{ O("%d %d %d",mSum,mA,mB); } return 0; }
DP
DP的思路在注释中,这里不再赘述
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100000 #define MAX (1<<30)-1 #define V vector<int> using namespace std; int a[LEN]; int s[LEN]; //s[i]表示dp[i]的连续序列从a的哪个元素开始的 int dp[LEN];//dp[i]存放以a[i]结尾的连续序列的最大和 int main(){ // freopen("1007.txt","r",stdin); int i,n; bool flag=0; //数组中的元素是否全部小鱼0 I("%d",&n); FF(i,n){ I("%d",&a[i]); if(a[i]>=0) flag=1; } if(!flag){ O("%d %d %d",0,a[0],a[n-1]); return 0; } //边界 dp[0]=a[0] ; //注意隐式赋值: s[0]=0 F(i,1,n){ //状态转移方程 if(dp[i-1]+a[i]>a[i]){ //放 dp[i]=dp[i-1]+a[i]; s[i]=s[i-1]; }else{ //不放 dp[i] =a[i]; s[i]=i; } } //遍历一遍,找到以哪个元素结尾,连续和最大 int k=0; F(i,1,n) { if(dp[i]>dp[k]){ k=i; } } O("%d %d %d",dp[k],a[s[k]],a[k]); return 0; }