1. 程式人生 > >最大子段和問題-蠻力法、分治法、動態規劃法

最大子段和問題-蠻力法、分治法、動態規劃法

蠻力法:

int maxSum1(int a[], int n){
    int i;
    int j;
    int maxSum = 0;

    for(i = 0; i < n; i++){
        int sum = 0;
        for(j = i; j < n; j++){
            sum += a[j];
            if(sum > maxSum){
                maxSum = sum;
            }
        }
    }


    return maxSum;

}

分治法:

int maxSum2(int left, int right, int a[]){
    int center , i;
    int sum, left_sum, right_sum;
    int left_max, right_max;

    if(left == right)
        return a[left] ;
    else{
            center = (left + right) / 2;
            left_sum = maxSum2(left, center, a);
            right_sum = maxSum2(center+1, right, a);
            sum = 0;
            left_max = 0;
            //求左邊的最大值
            for(i = center; i >= left; i--){
                sum += a[i];
                if(sum > left_max){
                    left_max = sum;
                }
            }
            sum = 0;
            right_max = 0;
            //求右邊的最大值
            for(i = center + 1; i <= right; i++){
                sum += a[i];
                if(sum > right_max){
                    right_max = sum;

                }
            }
            sum = right_max+ left_max;
            if(sum < left_sum)
                sum = left_sum;
            if(sum < right_sum)
                sum = right_sum;

    }
    return sum ;
}

動態規劃法:

void maxSum3(int a[], int n){
    int b[n];
    int i, j, s = n - 1;
    int maxSum = 0;
    b[0] = a[0]; //只有一個數時  最大子段和是其本身
    for(i = 1; i < n; i++){
        if(b[i - 1] > 0)
            b[i] = b[i - 1] + a[i];
        else{  //前面的值小於0  直接從當前原陣列開始
            b[i] = a[i];
        }
    }
 /*   printf("\n\n動態規劃法 列印b陣列:");
    for(i = 0; i < n; i++){
        printf("%d  ", b[i]);
    }
    printf("\n");
*/
    for(j = 0; j < n; j++){
        if(b[j] > maxSum){
            s = j;
            maxSum = b[j];

        }
    }
    printf("\n動態規劃法求出最大子段和為:%d", maxSum);

    for(i = s-1; i >= 0; i--){
        if(b[i] <= 0)
            break;
    }
    printf("\n\n列印最大子段:\n");
    for(i = i + 1; i <= s; i++){
        printf("%d  ", a[i]);
    }


}

完整程式碼:

#include <stdio.h>
#include <stdlib.h>
#define N 10
//判斷是否全為負數
int IsFuShu(int a[], int n){
    int i = 0;
    for(i = 0; i < n; i++){
        if(a[i] > 0)
            break;
    }
    if(i == n)
        return -1; //全是負數時
    else
        return 0; //有正數時


}

//蠻力法
//從第一個數開始,找第一個到最後一個數間最大欄位和;再從第二個數開始
int maxSum1(int a[], int n){
    int i;
    int j;
    int maxSum = 0;

    for(i = 0; i < n; i++){
        int sum = 0;
        for(j = i; j < n; j++){
            sum += a[j];
            if(sum > maxSum){
                maxSum = sum;
            }
        }
    }


    return maxSum;

}

//分治法
int maxSum2(int left, int right, int a[]){
    int center , i;
    int sum, left_sum, right_sum;
    int left_max, right_max;

    if(left == right)
        return a[left] ;
    else{
            center = (left + right) / 2;
            left_sum = maxSum2(left, center, a);
            right_sum = maxSum2(center+1, right, a);
            sum = 0;
            left_max = 0;
            //求左邊的最大值
            for(i = center; i >= left; i--){
                sum += a[i];
                if(sum > left_max){
                    left_max = sum;
                }
            }
            sum = 0;
            right_max = 0;
            //求右邊的最大值
            for(i = center + 1; i <= right; i++){
                sum += a[i];
                if(sum > right_max){
                    right_max = sum;

                }
            }
            sum = right_max+ left_max;
            if(sum < left_sum)
                sum = left_sum;
            if(sum < right_sum)
                sum = right_sum;

    }
    return sum ;
}

//動態
void maxSum3(int a[], int n){
    int b[n];
    int i, j, s = n - 1;
    int maxSum = 0;
    b[0] = a[0]; //只有一個數時  最大子段和是其本身
    for(i = 1; i < n; i++){
        if(b[i - 1] > 0)
            b[i] = b[i - 1] + a[i];
        else{  //前面的值小於0  直接從當前原陣列開始
            b[i] = a[i];
        }
    }
 /*   printf("\n\n動態規劃法 列印b陣列:");
    for(i = 0; i < n; i++){
        printf("%d  ", b[i]);
    }
    printf("\n");
*/
    for(j = 0; j < n; j++){
        if(b[j] > maxSum){
            s = j;
            maxSum = b[j];

        }
    }
    printf("\n動態規劃法求出最大子段和為:%d", maxSum);

    for(i = s-1; i >= 0; i--){
        if(b[i] <= 0)
            break;
    }
    printf("\n\n列印最大子段:\n");
    for(i = i + 1; i <= s; i++){
        printf("%d  ", a[i]);
    }


}

void Print(int a[], int n){
    printf("列印陣列:\n");
    int i;
    for(i = 0; i < n; i++){
        printf("%d   ", a[i]);
    }
}

void Creat(int a[]){
    int i,m;

    printf("輸入陣列的值:");
    for(i = 0; i < N; i++){
        scanf("%d", &m);
        a[i] = m;
    }

}
int main()
{
  //  int a[N] = {1,-1, 0, 2, -3, 4, -1, 0, -2, 4};
    int a[N];
    Creat(a);
    Print(a, N);
    int sum = IsFuShu(a, N);
    if(sum == -1)//全是負數值為0
        printf("最大子段和是0");
    else{
        sum = maxSum1(a, N);
        printf("\n蠻力法求出最大子段和是:%d\n" , sum);

        sum = maxSum2(0, N-1, a);
        printf("\n分治法求出最大子段和是:%d\n" , sum);

        maxSum3(a, N);


    }

    return 0;
}

執行結果:


相關推薦

排序問題(治法

蠻力法: 選擇排序法: 演算法思想:在剩餘序列中選出最小(或最大)的關鍵字,和剩餘序列的第一個關鍵字交換位置,依次選擇下去(每次掃描結束找出最小的一個元素依次放在前面的位置),直至使整個序列有序。 程式碼實習: #include<iostream> using names

演算法設計與分析--求大子問題(治法動態規劃法) C++實現

演算法設計與分析--求最大子段和問題 問題描述: 給定由n個整陣列成的序列(a1,a2, …,an),求該序列形如 的子段和的最大值,當所有整數均為負整數時,其最大子段和為0。 利用蠻力法求解: int maxSum(int a[],int n) { int ma

大子問題-治法動態規劃法

蠻力法:int maxSum1(int a[], int n){ int i; int j; int maxSum = 0; for(i = 0; i < n; i++){ int sum = 0; fo

大子問題:遞迴及動態規劃

問題描述 求一個序列的最大子段和即最大連續子序列之和。例如序列[4, -3, 5, -2, -1, 2, 6, -2]的最大子段和為11=[4+(-3)+5+(-2)+(-1)+(2)+(6)]。 1. 蠻力演算法 思想:從序列首元素開始窮舉

[C++] 動態規劃之矩陣連乘長公共子序列大子長單調遞增子序列

每次 種子 () return 避免 amp 可能 text com 一、動態規劃的基本思想   動態規劃算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。   將待求解問題分解成若幹個子問題,先求

順序表應用7:大子之分治遞迴(SDUT 3664)

#include <bits/stdc++.h> using namespace std; const int maxn = 50005; int num = 0; struct node { int *elem; int len; }; void Creatlist(

【算競賽進階指南】擴展大子POJ1050ToTheMax

ace 競賽 -a set 沒有 lac 嚴格 處理 初始 最大子段和 最大子段和可以利用貪心/DP的思想來解決,我這裏沒有嚴格證明,但是思考之後覺得很有道理,如果某一段字段和,不包括該數時,前段小於0,能麽加上該數不會變的更大,能麽當前子段和應該只有當前一個數字,如果大於

順序表應用7:大子之分治遞迴 SDUT

順序表應用7:最大子段和之分治遞迴法 Time Limit: 10 ms Memory Limit: 400 KiB Problem Description 給定n(1<=n<=50000)個整數(可能為負數)組成的序列a[1],a[2],a[3]

3664-順序表應用7:大子之分治遞迴-C語言

#include <stdio.h> #include <stdlib.h> int count=0; //定義全域性變數用來記錄遞迴次數 typedef struct{ int data[50010]; int length; }Lis

順序表應用7:大子之分治遞迴

 給定n(1<=n<=50000)個整數(可能為負數)組成的序列a[1],a[2],a[3],…,a[n],求該序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。當所給的整數均為負數時定義子段和為0,依此定義,所求的最優值為: Max{0,a[i]+a[i+1]+…+a[j]},1&

陣列中小值的二分求解

方法一:蠻力法 /**用最少的比較次數找出一袋金塊中最重的和最輕的**/ /**蠻力法,相當於一次排序*/ #include<iostream> using namespace std;

大子的DP算設計與其單元測試

his 最大子數組 利用 來看 中一 tco public art 容器 表情包形象取自番劇《貓咪日常》 那我也整一個 曾幾何時,筆者是個對算法這個概念漠不關心的人,由衷地感覺它就是一種和奧數一樣華而不實的存在,即便不使用任何算法的思想我一樣能寫出能跑的程序 直到一年前

C++學習(1):大子(多種解法)

多少 問題: code namespace 數據 組成 amp using () 問題:給定由n個數(可能為負數)組成的序列a1,a2,a3,...,an,求該序列子段和的最大值。 第一種解法:(最容易考慮的方法,將所有的子段一一相加,然後比較) 1 #include&

51Nod 1050 循環數組大子 | DP

urn F12 int ges href 中間 art space style Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 分析: 有兩種可能,第一種為正常從[1 - n]序列中的最大子字段和;第二種為數組的total_sum -

動態規劃 ------大子

動態規劃 函數 cnblogs png 規劃 font 3-9 .cn -- 1.最大子段和的問題描述 2.動態規劃的求解: 3.優化函數的遞推方程 4.動態規劃求解偽碼 5.動態規劃求解的小結: 動態規劃的

詳解 大子

最大 負數 nbsp 端點 關於 一段 描述 計數器 曾經 題目名稱:最大子段和 題目描述:給出一段序列,選出其中連續且非空的一段使得這段和最大。 輸入格式: 第一行是一個正整數N,表示了序列的長度。 第2行包含N個絕對值不大於10000的整數A[i],描述了這段序列。

1049 大子

return 51nod name 長度 black 最長 quest sin http 1049 最大子段和 基準時間限制:1 秒 空間限制:131072 KB 分值: 0 難度:基礎題 N個整數組成的序列a[1],a[2],a[3],…,a[n],求該序列如

數組的連續大子

簡單 IT 設置 OS case size_t 最大 退出 gin   問題描述:輸入是一個大小為n的整型數組,要求輸出數組的任何連續子數組中的最大值。例如:輸入的數組為array[10] = {31,-41,59,26,-53,58,97,-93,-23,84};輸出最

51nod1254 大子 V2

i+1 交換操作 最大子段和 body OS 另一個 體會 思路 處理 想了很久才體會出這道題的奧妙,愛恨交加的復雜情感。 思路: 題目要求必須做交換操作,那麽就有以下三種情況: 1.被交換的兩個數都在最大子段中; 2.被交換的兩個數都不在最大子段中; 3.被交換的兩個數

P1115大子

cst i++ ref lld 貪心 pri pre () href 題目:https://www.luogu.org/problemnew/show/P1115 很簡明的一道題; 這裏用了遞歸分治,然而似乎還有更簡單的做法(貪心)。 代碼如下: #include<