<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      最大子序列和問題

      最大子序列和問題

      問題描述:

          輸入一組整數,求出這組數字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那個序列。例如:

      序列:-2 11 -4 13 -5 -2,則最大子序列和為20。

      序列:-6 2 4 -7 5 3 2 -1 6 -9 10 -2,則最大子序列和為16。

       

      算法一:

      //窮舉法,復雜度O(n^3) 

      long maxSubSum1(const vector<int>& a) 

             long maxSum = 0; 

             for (int i = 0; i < a.size(); i++) 

            

                    for (int j = i; j < a.size(); j++) 

                   

                           long thisSum = 0; 

       

                           for (int k = i; k <= j; k++) 

                          

                                  thisSum += a[k]; 

                          

                           if (thisSum > maxSum) 

                                  maxSum = thisSum; 

                   

            

             return maxSum; 

      } 

      這是一個O(N^3) 的算法,算法本身很容易理解,而且很直觀的感覺做了很多無用操作。例如:i = 0, j = 3時,會計算a[0] + a[1] +…+ a[3];而當i = 0, j = 4時候又會計算a[0] + a[1] +…a[4]。

      算法二:

      通過撤出一個for循環來避免三次時間。

      //也是窮舉法,不過減去了上面的一些不必要操作O(n^2) 

      long maxSubSum2(const vector<int>& a) 

             long maxSum = 0; 

             for (int i = 0; i < a.size(); i++) 

            

                    long thisSum = 0; 

                    for (int j = i; j < a.size(); j++) 

                   

                           thisSum += a[j]; 

                           if (thisSum > maxSum) 

                                  maxSum = thisSum; 

                   

            

             return maxSum; 

      }

      這是一個非常直觀的窮舉法(比上面的分析還有簡單些),而且沒有多余重復的操作,復雜度為O(N^2) 。其中,thisSum表示a[i] + a[i+1] + … + a[j-1]。

       

       

      算法三:

          對這個問題,有一個相對復雜的O(NlogN)的解法,就是使用遞歸。如果要是求出序列的位置的話,這將是最好的算法了(因為我們后面還會有個O(N)的算法,但是不能求出最大子序列的位置)。該方法我們采用分治策略divide-and-conquer)。

      在我們例子中,最大子序列可能在三個地方出現,或者在左半部,或者在右半部,或者跨越輸入數據的中部而占據左右兩部分。前兩種情況遞歸求解,第三種情況的最大和可以通過求出前半部分最大和(包含前半部分最后一個元素)以及后半部分最大和(包含后半部分的第一個元素)相加而得到。

      //遞歸法,復雜度是O(nlogn) 

      long maxSumRec(const vector<int>& a, int left, int right) 

             if (left == right) 

            

                    if (a[left] > 0) 

                           return a[left]; 

                    else 

                           return 0; 

            

             int center = (left + right) / 2; 

             long maxLeftSum = maxSumRec(a, left, center); 

             long maxRightSum = maxSumRec(a, center+1, right); 

       

             //求出以左邊對后一個數字結尾的序列最大值 

             long maxLeftBorderSum = 0, leftBorderSum = 0; 

             for (int i = center; i >= left; i--) 

            

                    leftBorderSum += a[i]; 

                    if (leftBorderSum > maxLeftBorderSum) 

                           maxLeftBorderSum = leftBorderSum; 

            

       

             //求出以右邊對后一個數字結尾的序列最大值 

             long maxRightBorderSum = 0, rightBorderSum = 0; 

             for (int j = center+1; j <= right; j++) 

            

                    rightBorderSum += a[j]; 

                    if (rightBorderSum > maxRightBorderSum) 

                           maxRightBorderSum = rightBorderSum; 

            

       

             return max3(maxLeftSum, maxRightSum,  

                    maxLeftBorderSum + maxRightBorderSum); 

       

      long maxSubSum3(const vector<int>& a) 

             return maxSumRec(a, 0, a.size()-1); 

      }

      另外max3(long,long,long)表示求三個long中的最大值:

      //求出三個long中的最大值 

      long max3(long a, long b, long c) 

             if (a < b) 

            

                    a = b; 

            

             if (a > c) 

                    return a; 

             else 

                    return c; 

      }

      對這個算法進行分析:

      T(1) = 1 

      T(N) = 2T(N/2) + O(N) 

      最后得出算法的復雜度為:O(NlogN)

       

      算法四:

      下面介紹一個線性的算法,這個算法是許多聰明算法的典型:運行時間是明顯的,但是正確性則很不明顯(不容易理解)。

      //線性的算法O(N) 

      long maxSubSum4(const vector<int>& a) 

             long maxSum = 0, thisSum = 0; 

             for (int j = 0; j < a.size(); j++) 

            

                    thisSum += a[j]; 

                    if (thisSum > maxSum) 

                           maxSum = thisSum; 

                    else if (thisSum < 0) 

                           thisSum = 0; 

            

             return maxSum; 

      }

          很容易理解時間界O(N) 是正確的,但是要是弄明白為什么正確就比較費力了。其實這個是算法二的一個改進。分析的時候也是i代表當前序列的起點,j代表當前序列的終點。如果我們不需要知道最佳子序列的位置,那么i就可以優化掉。

          重點的一個思想是:如果a[i]是負數那么它不可能代表最有序列的起點,因為任何包含a[i]的作為起點的子序列都可以通過用a[i+1]作為起點來改進。類似的有,任何的負的子序列不可能是最優子序列的前綴。例如說,循環中我們檢測到從a[i]a[j]的子序列是負數,那么我們就可以推進i關鍵的結論是我們不僅可以把i推進到i+1,而且我們實際可以把它一直推進到j+1。

          舉例來說,令pi+1j之間的任何一個下標,由于前面假設了a[i]+…+a[j]是負數,則開始于下標p的任意子序列都不會大于在下標i并且包含從a[i]a[p-1]的子序列對應的子序列(j是使得從下標i開始成為負數的第一個下標)。因此,把i推進到j+1是安全的,不會錯過最優解。注意的是:雖然,如果有以a[j]結尾的某序列和是負數就表明了這個序列中的任何一個數不可能是與a[j]后面的數形成的最大子序列的開頭,但是并不表明a[j]前面的某個序列就不是最大序列,也就是說不能確定最大子序列在a[j]前還是a[j]后,即最大子序列位置不能求出。但是能確保maxSum的值是當前最大的子序列和。這個算法還有一個有點就是,它只對數據進行一次掃描,一旦a[j]被讀入處理就不需要再記憶。它是一個聯機算法

       

      聯機算法:在任意時刻算法都能夠對它已讀入的數據給出當前數據的解。 

       

      常量空間線性時間的聯機算法幾乎是完美的算法。

       

      附錄:

      程序測試:

      先通過文件讀寫函數產生一組隨機數并且讀入到一個vector<int>中:

       

      //COUNTMAX_NUM分別表示隨機數個數和最大值 

      const long COUNT = 1000; 

      const int MAX_NUM = 200; 

       

      //讀文件 

      bool readFile(vector<int>& input, string fileName) 

             ifstream infile(fileName.c_str()); 

             if (!infile) 

                    return false

             int s; 

             while(infile>>s) 

            

                    input.push_back(s); 

            

             return true

       

      //寫大量隨機測試數據 

      bool writeTestData(string fileName) 

             ofstream outfile(fileName.c_str()); 

             if (!outfile) 

                    return false

             srand((unsigned)time(NULL)); 

             for (int i = 0; i < COUNT; i++) 

            

                    if (rand() % 2 == 0) 

                           outfile << rand() % MAX_NUM << '\n'

                    else 

                           outfile << ~(rand() % MAX_NUM) << '\n'

            

             return true

      }

      測試可得:

      COUNT = 1000的時候maxSubSum1()要等10s,后三個很快。

      COUNT = 10000的時候maxSubSum2()要等8s,后兩個很快。

      COUNT = 1000000的時候maxSubSum3()要等10smaxSubSum4()要等4s。

      其實當COUNT = 1000000這個時候但是作文件讀寫就要很耗時了,光是in.txt就達到了4.7MB了。

      COUNT = 10000000的時候光是文件讀寫就要半分鐘,in.txt達到了47.2MB,這時候再做maxSubSum3()maxSubSum4()的比較,maxSubSum4()需要56s,而maxSubSum3()這時候需要85s(包括了讀文件的時間)??梢姅祿勘容^大的情況下O(NlogN)的遞歸算法也是可行的,并不比O(N)低很多。尤其在要求出最大子序列位置的情況下,分治遞歸算法體現了強大的威力。

       

      程序源碼:

      #include <iostream>

      #include <string>

      #include <vector>

      #include <fstream>

      #include <cstdlib>

      #include <ctime>

       

      using namespace std;

       

      //COUNTMAX_NUM分別表示隨機數個數和最大值

      const long COUNT = 10000;

      const int MAX_NUM = 200;

       

      //讀文件

      bool readFile(vector<int>& input, string fileName)

      {

          ifstream infile(fileName.c_str());

          if (!infile)

              return false;

          int s;

          while(infile>>s)

          {

              input.push_back(s);

          }

          return true;

      }

       

      //寫大量隨機測試數據

      bool writeTestData(string fileName)

      {

          ofstream outfile(fileName.c_str());

          if (!outfile)

              return false;

          srand((unsigned)time(NULL));

          for (int i = 0; i < COUNT; i++)

          {

              if (rand() % 2 == 0)

                  outfile << rand() % MAX_NUM << '\n';

              else

                  outfile << ~(rand() % MAX_NUM) << '\n';

          }

          return true;

      }

       

      //窮舉法

      long maxSubSum1(const vector<int>& a)

      {

          long maxSum = 0;

          for (int i = 0; i < a.size(); i++)

          {

              for (int j = i; j < a.size(); j++)

              {

                  long thisSum = 0;

       

                  for (int k = i; k <= j; k++)

                  {

                      thisSum += a[k];

                  }

                  if (thisSum > maxSum)

                  maxSum = thisSum;

              }

          }

          return maxSum;

      }

       

      //也是窮舉法,不過減去了上面的一些不必要操作O(n^2)

      long maxSubSum2(const vector<int>& a)

      {

          long maxSum = 0;

          for (int i = 0; i < a.size(); i++)

          {

              long thisSum = 0;

              for (int j = i; j < a.size(); j++)

              {

                  thisSum += a[j];

                  if (thisSum > maxSum)

                      maxSum = thisSum;

              }

          }

          return maxSum;

      }

       

      //遞歸法,復雜度是O(nlogn)

      long max3(long a, long b, long c)

      {

          if (a < b)

          {

              a = b;

          }

          if (a > c)

              return a;

          else

          return c;

      }

       

      long maxSumRec(const vector<int>& a, int left, int right)

      {

          if (left == right)

          {

              if (a[left] > 0)

                  return a[left];

              else

                  return 0;

          }

          int center = (left + right) / 2;

          long maxLeftSum = maxSumRec(a, left, center);

          long maxRightSum = maxSumRec(a, center+1, right);

       

          //求出以左邊對后一個數字結尾的序列最大值

          long maxLeftBorderSum = 0, leftBorderSum = 0;

          for (int i = center; i >= left; i--)

          {

              leftBorderSum += a[i];

              if (leftBorderSum > maxLeftBorderSum)

                  maxLeftBorderSum = leftBorderSum;

          }

       

          //求出以右邊對后一個數字結尾的序列最大值

          long maxRightBorderSum = 0, rightBorderSum = 0;

          for (int j = center+1; j <= right; j++)

          {

              rightBorderSum += a[j];

              if (rightBorderSum > maxRightBorderSum)

                  maxRightBorderSum = rightBorderSum;

          }

       

          return max3(maxLeftSum, maxRightSum,

          maxLeftBorderSum + maxRightBorderSum);

      }

       

      long maxSubSum3(const vector<int>& a)

      {

          return maxSumRec(a, 0, a.size()-1);

      }

       

      //線性的算法O(N)

      long maxSubSum4(const vector<int>& a)

      {

          long maxSum = 0, thisSum = 0;

          for (int j = 0; j < a.size(); j++)

          {

              thisSum += a[j];

              if (thisSum > maxSum)

                  maxSum = thisSum;

              else if (thisSum < 0)

                  thisSum = 0;

          }

          return maxSum;

      }

       

      int main ()

      {

          vector<int> input;

          /**

          if (!writeTestData("in.txt"))

          {

              cout << "寫文件錯誤" << endl;

          }

          */

       

          if (readFile(input, "in.txt"))

          {

              //cout << maxSubSum1(input) << endl;

              //cout << maxSubSum2(input) << endl;

              cout << maxSubSum3(input) << endl;

              cout << maxSubSum4(input) << endl;

          }

       

          return 0;

      }

      posted @ 2009-04-25 14:49  InfantSorrow  閱讀(36781)  評論(22)    收藏  舉報
      主站蜘蛛池模板: 国产美女69视频免费观看| 亚洲嫩模喷白浆在线观看| 国产精品一码在线播放| 亚洲精品一区二区在线播| 国产综合久久99久久| 久操线在视频在线观看| 大地资源中文第三页| 一区二区三区一级黄色片| 亚洲理论在线A中文字幕| 伊人成人在线视频免费| 无套内谢少妇高清毛片| 国产日产亚洲系列av| 久久这里只精品热免费99| 精品国产一区二区三区麻豆| 国产成人午夜福利精品| 高清自拍亚洲精品二区| 中文字幕av中文字无码亚| 国产WW久久久久久久久久| 免费观看在线A级毛片| 白山市| 日本福利一区二区精品| 人妻精品人妻无码一区二区三区| 国产老妇伦国产熟女老妇高清 | 国产精品久久蜜臀av| 大港区| 国产资源精品中文字幕| 国产成人小视频| 亚洲精品揄拍自拍首页一| 国内精品视频一区二区三区| 和黑人中出一区二区三区| 久久96热在精品国产高清| 无码天堂亚洲国产av麻豆| 麻豆精品传媒一二三区| 国产精品自拍一二三四区| 成人午夜在线观看日韩| 亚洲日本韩国欧美云霸高清| 巨爆乳中文字幕爆乳区| 久久久精品2019中文字幕之3| 桃花岛亚洲成在人线AV| 亚洲乱码精品久久久久..| 日韩精品人妻中文字幕|