1. 程式人生 > >hdu 1003 Max Sum(最大連續子序列和) (學了一下分治)

hdu 1003 Max Sum(最大連續子序列和) (學了一下分治)

都不知道以前刷杭電是怎麼做的最大連續子序列和,仔細一想,我以前好像是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);
    }