大一时随便水题时碰到了hdu1003,大抵是初学,看了别人的代码后来自己也A掉了,但是没有了解思想。现在看来又有了新的收获。
这应该是刘汝佳的一道将算法复杂度的例题,给出了分治O(nlogn),预处理O(n^2),朴素O(n^3)的算法并进行比较。
题目大意是给出一串数字a[1]~a[n],要求出这串数字中和最大的子串a[i]+..a[j],并输出i,j。
分治算法没去看,先给出O(n^2)的算法。
#include <iostream> #include <cstdio> using namespace std; const int max_n=99999; int sum[max_n]; int pre[max_n]; int main() { int ncase,n,max; scanf("%d",&ncase); for(int ii=1;ii<=ncase;ii++) { scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&pre[i]); sum[0]=0; for(int i=1; i<=n; i++) sum[i]=sum[i-1]+pre[i]; max=pre[1]; int l=pre[1]; int r=pre[n]; for(int i=1; i<=n; i++) for(int j=1; j<=i; j++) if(sum[i]-sum[j-1]>max) { max=sum[i]-sum[j-1]; l=j; r=i; } printf("Case %d:\n",ii); printf("%d %d %d\n",max,l,r); if(ii!=ncase) printf("\n"); } return 0; }预处理原始pre,求出sum数组,显然题目最后的复杂度是O(n^2).
TLE了,必须优化才行,换了另一种方法,不知道是不是属于动态规划,反正是有一点那种思想在里面。
基本思想就是一边扫描数组一边更新max。
#include<stdio.h> void main() { int T,ncase,num; int start,stemp,end,etemp; int max,sum,i; int c[100002]; scanf("%d",&T); for(ncase=1;ncase<=T;ncase++) { scanf("%d",&num); for(i=1;i<=num;i++) scanf("%d",&c[i]); max=-1010; sum=0; start=1; stemp=1; for (i = 1; i <= num; i++) { sum=sum+c[i]; if(sum>max) {max=sum;start=stemp;end=i;} if(sum<0) {sum=0;stemp=i+1;} } printf("Case %d:\n",ncase); printf("%d %d %d\n",max,start,end); if(ncase!=T) printf("\n"); } }
这是之前的一道题目,然后最近看到的hdu1231其实就是一样的思路。
下面给上hdu1231的AC代码:
#include<stdio.h> #include<iostream> using namespace std; int main() { int num; int start,stemp,end; int max,sum,i; int c[100002]; while(scanf("%d",&num)==1) { if(num==0) break; for(i=1;i<=num;i++) scanf("%d",&c[i]); max=-1010; sum=0; start=1; stemp=1; for (i = 1; i <= num; i++) { sum=sum+c[i]; if(sum>max) {max=sum;start=stemp;end=i;} if(sum<0) {sum=0;stemp=i+1;} } if(max<0) { max=0; start=1; end=num; } printf("%d %d %d\n",max,c[start],c[end]); } return 0; }今天自行车竟然被偷了,真不爽啊!!!!