hdu 1003 Max Sum(最大連續子序列和) (學了一下分治)
阿新 • • 發佈:2019-02-20
都不知道以前刷杭電是怎麼做的最大連續子序列和,仔細一想,我以前好像是dp寫的, 然後現在再來寫居然發現不能快速寫出來了。。 真是坑啊。。
看了自己以前寫的最大連續子序列和的程式碼, 真的是讓我噁心死了。。 程式碼風格慘不忍睹
前兩天在大白書看到最大連續子序列和可以用分治去做,可是某渣都不知道。。 然後就好奇的做了一下。 發現自己不會用分治去做
最後看了六種方法求最大連續子序列和:
感覺有點收穫。。
分治演算法一般分為如下3個步驟:
劃分問題: 把問題的例項劃分為子問題
遞迴求解: 遞迴解決子問題
合併問題: 合併子問題的解得到原問題的解
分治法程式碼:
#include <cstdio> #include <cstring> #define maxn 100005 int a[maxn]; struct node { int l, r; int sum; node(int x, int y, int z): l(x), r(y), sum(z){} }; node maxsum(int a[], int l, int r) //區間[l,r)的最大值 { // printf("%d %d\n",l, r); if(l+1 == r|| l==r) return node(l, l, a[l]); int mid= (l + r)/ 2; node sum_l= maxsum(a, l, mid); //左區間[l, mid)的最大值 node sum_r= maxsum(a, mid, r);//右區間[mid, r)的最大值 node M= sum_l.sum >= sum_r.sum ? sum_l : sum_r; int v= 0, mid_l= a[mid-1],mid_r= a[mid], x= mid-1, y= mid; for(int i= mid-1; i>= l; i--)//從分界點開始往左,左邊取最小,所以a[i]>= 0 { v+= a[i]; if(v>= mid_l) mid_l= v, x= i; } v= 0; for(int i= mid; i< r; i++)//從分界點開始往右,右邊取最小,所以a[i]>0 { v+= a[i]; if(v> mid_r) mid_r= v, y= i; } if(mid_l + mid_r < M.sum) return M; else return node(x, y, mid_l+mid_r); } int main() { int C; scanf("%d",&C); for(int c= 1; c<= C; c++) { int n; scanf("%d",&n); for(int i= 1; i<= n; i++) scanf("%d",&a[i]); node ans= maxsum(a, 1, n+1); if(c!= 1) printf("\n"); printf("Case %d:\n%d %d %d\n",c, ans.sum, ans.l, ans.r); } return 0; }
動態規劃程式碼:
#include <cstdio> #include <cstring> #define maxn 100005 int sum[maxn]; int main() { int T; scanf("%d",&T); for(int c= 1; c<= T; c++) { int n, num; scanf("%d %d",&n,&num); int anss= 1, anst= 1; int max= num; sum[1]= num; int s= 1, t= 1; for(int i= 2; i<= n; i++) { scanf("%d",&num); sum[i]= num; if(sum[i-1] + num >= num) { sum[i]= sum[i-1] + num; t++; } else { s= i; t= i; } if(sum[i]> max) { max= sum[i]; anss= s; anst= t; } } if(c!= 1) printf("\n"); printf("Case %d:\n%d %d %d\n",c,max,anss,anst); }