1. 程式人生 > >演算法競賽中的時間複雜度選擇——以最大連續和問題為例

演算法競賽中的時間複雜度選擇——以最大連續和問題為例

最大連續和問題

最大連續和問題。給出一個長度為n的序列 A1,A2,,An,求最大連續和。換句話說,要求找到1ijn,使得Ai+Ai+1+...+Aj儘量大。

時間複雜度為n3的演算法

LL maxConSumN3(LL *a, LL n) {
    tot = 0;
    conSum = -INF;
    for(LL i = 0; i < n; i++) {
        for(LL j = i; j < n; j++) {
            LL sum = 0;
            for(LL k = i; k <= j; k++) {
                sum
+= a[k]; tot++; } if(sum > conSum) { conSum = sum; } } } return conSum; }

時間複雜度為n2的演算法

LL maxConSumN2(LL *a, LL n) {
    tot = 0;
    conSum = -INF;
    for(LL i = 0; i < n; i++) {
        LL sum = 0;
        for
(LL j = i; j < n; j++) { sum += a[j]; tot++; if(sum > conSum) { conSum = sum; } } } return conSum; }

時間複雜度為nlog2n的演算法

// 採用分治法
// 對半劃分
// 遞迴求解左半邊和右半邊的最大連續和
// 遞迴邊界為left=right
// 求解左右連線部分的最大連續和
// 合併子問題:取三者最大值
LL division(LL *a, LL lef, LL righ) {
    // 遞迴邊界
if(lef == righ) { return a[lef]; } LL center = lef + (righ - lef) / 2; // 左半邊最大連續和 LL maxLeftSum = division(a, lef, center); // 右半邊最大連續和 LL maxRightSum = division(a, center + 1, righ); // 左連線部分最大和 LL maxLeftConSum = -INF; LL leftConSum = 0; for(LL i = center; i >= lef; i--) { leftConSum += a[i]; tot++; if(leftConSum > maxLeftConSum) { maxLeftConSum = leftConSum; } } // 右連線部分最大和 LL maxRightConSum = -INF; LL rightConSum = 0; for(LL i = center + 1; i <= righ; i++) { rightConSum += a[i]; tot++; if(rightConSum > maxRightConSum) { maxRightConSum = rightConSum; } } return max(max(maxLeftSum, maxRightSum), maxLeftConSum + maxRightConSum); } LL maxConSumNLogN(LL *a, LL n) { return division(a, 0, n - 1); }

時間複雜度為n的演算法

LL maxConSumN(LL *a, LL n) {
    conSum = -INF;
    LL sum = 0;
    tot = 0;
    for(int i = 0; i < n; i++) {
        sum += a[i];
        tot++;
        if(sum < 0) {
            sum = 0;
        }
        if(sum > conSum) {
            conSum = sum;
        }
    }
    return conSum;
}

測試主程式

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;
const LL INF = 100000000;

// 總執行次數
LL tot;
// 最大連續和
LL conSum;

// 求最大連續和問題
// n^3的演算法
LL maxConSumN3(LL *a, LL n) {
    tot = 0;
    conSum = -INF;
    for(LL i = 0; i < n; i++) {
        for(LL j = i; j < n; j++) {
            LL sum = 0;
            for(LL k = i; k <= j; k++) {
                sum += a[k];
                tot++;
            }
            if(sum > conSum) {
                conSum = sum;
            }
        }
    }
    return conSum;
}

// n^2的演算法
LL maxConSumN2(LL *a, LL n) {
    tot = 0;
    conSum = -INF;
    for(LL i = 0; i < n; i++) {
        LL sum = 0;
        for(LL j = i; j < n; j++) {
            sum += a[j];
            tot++;
            if(sum > conSum) {
                conSum = sum;
            }
        }
    }
    return conSum;
}

// nlogn的演算法
// 採用分治法
// 對半劃分
// 遞迴求解左半邊和右半邊的最大連續和
// 遞迴邊界為left=right
// 求解左右連線部分的最大連續和
// 合併子問題:取三者最大值
LL division(LL *a, LL lef, LL righ) {
    // 遞迴邊界
    if(lef == righ) {
        return a[lef];
    }
    LL center = lef + (righ - lef) / 2;
    // 左半邊最大連續和

    LL maxLeftSum = division(a, lef, center);
    // 右半邊最大連續和
    LL maxRightSum = division(a, center + 1, righ);
    // 左連線部分最大和
    LL maxLeftConSum = -INF;
    LL leftConSum = 0;
    for(LL i = center; i >= lef; i--) {
        leftConSum += a[i];
        tot++;
        if(leftConSum > maxLeftConSum) {
            maxLeftConSum = leftConSum;
        }
    }
    // 右連線部分最大和
    LL maxRightConSum = -INF;
    LL rightConSum = 0;
    for(LL i = center + 1; i <= righ; i++) {
        rightConSum += a[i];
        tot++;
        if(rightConSum > maxRightConSum) {
            maxRightConSum = rightConSum;
        }
    }
    return max(max(maxLeftSum, maxRightSum), maxLeftConSum + maxRightConSum);
}

LL maxConSumNLogN(LL *a, LL n) {
    return division(a, 0, n - 1);
}

// n的演算法
LL maxConSumN(LL *a, LL n) {
    conSum = -INF;
    LL sum = 0;
    tot = 0;
    for(int i = 0; i < n; i++) {
        sum += a[i];
        tot++;
        if(sum < 0) {
            sum = 0;
        }
        if(sum > conSum) {
            conSum = sum;
        }
    }
    return conSum;
}

int main() {
    LL a[] = {-2, 3, 4, 5, -6, 7, -1, 2, 6};
    cout << "時間複雜度為N^3的演算法:" << maxConSumN3(a, 9);
    cout << "\t 計算次數為:" << tot << endl;

    cout << "時間複雜度為N^2的演算法:" << maxConSumN2(a, 9);
    cout << "\t 計算次數為:" << tot << endl;

    tot = 0;
    cout << "時間複雜度為NLogN的演算法:" << maxConSumNLogN(a, 9);
    cout << "\t 計算次數為:" << tot << endl;

    cout << "時間複雜度為N的演算法:" << maxConSumN(a, 9);
    cout << "\t\t 計算次數為:" << tot << endl;

    return 0;
}

輸出結果為

時間複雜度為N^3的演算法:20         計算次數為:165
時間複雜度為N^2的演算法:20         計算次數為:45
時間複雜度為NLogN的演算法:20       計算次數為:29
時間複雜度為N的演算法:20           計算次數為:9

Process returned 0 (0x0)   execution time : 0.196 s
Press any key to continue.

演算法競賽中的時間複雜度選擇

假設機器速度是每秒108次基本運算,運算量為n3n2nlog2nn2n(如子集列舉)和n!(如排列列舉)的演算法,在1秒之內能解決最大問題規模n,如表所示:

運算量 n! 2n n3 n2 nlog2n n
最大規模 11 26 464 10000 4.5106 100000000
速度擴大兩倍以後 11 27 584 14142 8.6106 200000000
運算量隨著規模的變化

表還給出了機器速度擴大兩倍後,演算法所能解決規模的對比。可以看出,n!2n不僅能解決的問題規模非常小,而且增長緩慢;最快的nlog2nn演算法不僅解決問題的規模大,而且增長快。漸進時間複雜為多項式的演算法稱為多項式時間演算法(polymonial-time algorithm),也稱有效演算法;而n!或者2n這樣的低效的演算法稱為指數時間演算法(exponentialtime algorithm)。

不過需要注意的是,上界分析的結果在趨勢上能反映演算法的效率,但有兩個不精確性: 一是公式本身的不精確性。例如,“非主流”基本操作的影響、隱藏在大O記號後的低次項和最高項係數;二是對程式實現細節與計算機硬體的依賴性,例如,對複雜表示式的優化計算、把記憶體訪問方式設計得更加“cache友好”等。在不少情況下,演算法實際能解決的問題規模與表所示有著較大差異。

儘管如此,表還是有一定借鑑意義的。考慮到目前主流機器的執行速度,多數演算法競賽題目所選取的資料規模基本符合此表。例如,一個指明n8的題目,可能n!的演算法已經足夠,n20的題目需要用到2n的演算法,而n300的題目可能必須用至少n3的多項式時間演算法了。

相關推薦

演算法競賽時間複雜選擇——連續問題

最大連續和問題 最大連續和問題。給出一個長度為n的序列 A1,A2,…,An,求最大連續和。換句話說,要求找到1≤i≤j≤n,使得Ai+Ai+1+...+Aj儘量大。 時間複雜度為n3的演算法 LL maxConSumN3(LL *a, L

連續演算法分析

學習劉汝佳老師的《演算法競賽》總結 最大連續和問題 給出一個長度為n的序列A1,A2,……,An,要求找到1≤i≤j≤n,使得Ai+Ai+1+……+Aj儘量大。 一.使用列舉,程式如下: tot = 0; best = A[1]; //初始最大值

演算法時間複雜概括——o(1)、o(n)、o(logn)、o(nlogn)

在描述演算法複雜度時,經常用到o(1), o(n), o(logn), o(nlogn)來表示對應演算法的時間複雜度。這裡進行歸納一下它們代表的含義:這是演算法的時空複雜度的表示。不僅僅用於表示時間複雜度,也用於表示空間複雜度。   O後面的括號中有一個函式,指明某個演算法的

計數排序,傳說時間複雜O(n+k)的排序演算法

基本思想 假設數序列中小於元素a的個數為n,則直接把a放到第n+1個位置上。當存在幾個相同的元素時要做適當的調整,因為不能把所有的元素放到同一個位置上。計數排序假設輸入的元素都是0到k之間的整數。 回到頂部 參考程式碼 #include &

【轉】演算法時間複雜概括——o(1)、o(n)、o(logn)、o(nlogn)

       在描述演算法複雜度時,經常用到o(1), o(n), o(logn), o(

演算法分析(時間複雜空間複雜

演算法分析(時間複雜度和空間複雜度) 對於一個給定的演算法需要做兩項分析,第一就是證明演算法的正確性,第二就是計算演算法的複雜度。演算法的複雜度包括時間複雜度和空間複雜度。 1  度量演算法效率的方法 共存在兩種方法:事後統計法和事前分析估計演算法。 事後統計法:先將演算法實現,然

初學者學演演算法|從時間複雜認識常見演演算法(一)

O(log n):二分搜尋法時間複雜度為 O(log n) 的演演算法(這邊的 log 都是以二為底),代表當輸入的數量是 n 時,執行的步驟數會是 log n。(讓忘記 log 是什麼的同學們複習一下,當 log n = x 的意思是 n = 2^x,如果這部分的腦細胞尚未復活,且讓我們先記住 n = 2^

演算法分析之時間複雜與空間複雜

演算法的評價指標主要是正確性,健壯性、可讀性和有效性4個方面,有效性又包括時間複雜度和空間複雜度。 演算法的時間複雜度和空間複雜度通常採用數量級的形式來表示,而數量的形式有常量階、對數階、線性階、線性對數階、平方階、立方階、指數階、階乘階等。若演算法的時間複雜度和空間複雜度

preNoip時間複雜的計算

特徵方程法解一階線性代數遞推式 數列{ana_nan​}滿足a1=b,an+1=can+da_1=b,a_{n+1}=ca_n+da1​=b,an+1​=can​+d,求該數列的通項公式 針對遞推關係

KMP演算法介紹及時間複雜分析

概念:字串中 一個字元前面的字串 的字首與字尾的最長匹配長度(短的那個字串) 注意:字首與字尾不可以是整個子字串 例如:a b c a b c d , d位置的最長匹配長度為3,abc 與 abc 匹配 Next陣列:長度與字串長度一致,每個位置儲存對應字元的最長匹配長

演算法分析神器—時間複雜

時間複雜度是學習演算法的基石,今天我們來聊聊為什麼要引入時間複雜度,什麼是時間複雜度以及如何去算一個演算法的時間複雜度 刻畫演算法的執行時間 某日,克叫來了慧子打算給他補習補習一下基礎知識,只見克寫了一段非常簡單的程式碼 克 你說一下這段程式碼會執行多長時間

面試題:top k演算法O(n)時間複雜

在《資料結構與演算法分析--c語言描述》一書,第7章第7.7.6節中,闡述了一種在平均情況下,時間複雜度為O(N)的快速選擇演算法。如下述文字: 選取S中一個元素作為樞紐元v,將集合S-{v}分割成S1和S2,就像快速排序那樣 如果k <= |S1|,那麼第k個最小

常用排序演算法穩定性、時間複雜分析

1、  選擇排序、快速排序、希爾排序、堆排序不是穩定的排序演算法,        氣泡排序、插入排序、歸併排序和基數排序是穩定的排序演算法。 2、研究排序演算法的穩定性有何意義?   首先,排序演算法的穩定性大家應該都知道,通俗地講就是能保證排序前兩個相等的資

淺談直接插入排序演算法思想以及時間複雜分析

研究意義 直接插入排序是最基本的一種排序演算法,其思想簡單,容易掌握,對後期的學習也有一定的幫助。 必備知識(之後不再敘述) 排序:將一組雜亂無章的資料排列成一個按關鍵字有序的序列。 穩定性:關鍵值相

排序演算法 (穩定性時間複雜分析)

1、  選擇排序、快速排序、希爾排序、堆排序不是穩定的排序演算法,        氣泡排序、插入排序、歸併排序和基數排序是穩定的排序演算法。 2、研究排序演算法的穩定性有何意義?   首先,排序演算法的穩定性大家應該都知道,通俗地講就是能保證排序前兩個相等的資

BZOJ2038: [2009國家集訓隊]小Z的襪子(hose) 莫隊演算法 莫隊演算法講解及時間複雜證明

2038: [2009國家集訓隊]小Z的襪子(hose) Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 7088  Solved: 3258

自己整理的幾種常見排序演算法,及時間複雜空間複雜。c++程式設計

/***************************************************** copyright (C), 2014-2015, Lighting Studio. Co.,     Ltd.  File name: Author:fhb  

各種排序演算法比較:時間複雜,空間複雜

時間複雜度 n^2表示n的平方,選擇排序有時叫做直接選擇排序或簡單選擇排序 排序方法 平均時間 最好時間 最壞時間 桶排序(不穩定) O(n) O(n) O(n) 基數排序(穩定) O(n) O(n) O(n) 歸併排序(穩定) O(nlogn) O(nlogn) O(nlogn) 快速排序(不穩定)

有1,2,....一直到n的無序陣列,求排序演算法,要求時間複雜O(n),空間複雜O(1)

http://blog.csdn.net/dazhong159/article/details/7921527 1、有1,2,....一直到n的無序陣列,求排序演算法,並且要求時間複雜度為O(n),空間複雜度O(1),使用交換,而且一次只能交換兩個數。 #include &

演算法 歸併排序的複雜分析(含圖解流程Master公式)

圖解流程 整體流程如下: 細節流程: 第一步: 第二步: 第三步: 第四步: 第五步: 第六步: 第七步: 第八步: