簡單dp算法——百鍊06:股票買賣

06:股票買賣

點擊打開鏈接http://bailian.openjudge.cn/2016acm/06/


總時間限制:

1000ms

內存限制:

65536kB

描述

最近越來越多的人都投身股市,阿福也有點心動了。謹記着“股市有風險,入市需謹慎”,阿福決定先來研究一下簡化版的股票買賣問題。

假設阿福已經準確預測出了某隻股票在未來 N 天的價格,他希望買賣兩次,使得獲得的利潤最高。爲了計算簡單起見,利潤的計算方式爲賣出的價格減去買入的價格。

同一天可以進行多次買賣。但是在第一次買入之後,必須要先賣出,然後纔可以第二次買入。

現在,阿福想知道他最多可以獲得多少利潤。

輸入
輸入的第一行是一個整數 T (T <= 50) ,表示一共有 T 組數據。
接下來的每組數據,第一行是一個整數 N (1 <= N <= 100, 000) ,表示一共有 N 天。第二行是 N 個被空格分開的整數,表示每天該股票的價格。該股票每天的價格的絕對值均不會超過 1,000,000 。
輸出
對於每組數據,輸出一行。該行包含一個整數,表示阿福能夠獲得的最大的利潤。
樣例輸入
3
7
5 14 -2 4 9 3 17
6
6 8 7 4 1 -2
4
18 9 5 2
樣例輸出
28
2
0
提示
對於第一組樣例,阿福可以第 1 次在第 1 天買入(價格爲 5 ),然後在第 2 天賣出(價格爲 14 )。第 2 次在第 3 天買入(價格爲 -2 ),然後在第 7 天賣出(價格爲 17 )。一共獲得的利潤是 (14 - 5) + (17 - (-2)) = 28
對於第二組樣例,阿福可以第 1 次在第 1 天買入(價格爲 6 ),然後在第 2 天賣出(價格爲 8 )。第 2 次仍然在第 2 天買入,然後在第 2 天賣出。一共獲得的利潤是 8 - 6 = 2
對於第三組樣例,由於價格一直在下跌,阿福可以隨便選擇一天買入之後迅速賣出。獲得的最大利潤爲 0



解題思路:
        用兩個數組predp[ i ](第 i 天之前收益最大,包括第 i 天,且只買賣一次),post[ i ](第 i 天之後收益最大,包括第 i 天,且只買賣一次)。 給predp[ i ]賦值時,需要找到第 i 天(包括 i)之前最小的股市價格minn,然後用第 i 天的價格減去minn的值與predp[ i - 1 ]相比最大的就是predp[ i ]的值(因爲predp[ i ]始終要保持第 i 天之前最大收益); 給postdp[ i ]賦值時,需要找到第 i 天(包括 i)之後最大的股市價格maxn,然後用maxn減去第 i 天的價格的值與postdp[ i + 1 ] 相比最大的就是postdp[ i ]的值(因爲postdp[ i ]始終要保持第 i 天之後最大收益)。最後把predp[ i ] ,postdp[ i ] 相加,找到其中最大的值就是這幾天交易兩次最大的盈利。(第 i 天之前最大的收益 + 第 i 天之後最大的收益)。
       理解了嗎?如果理解了還有一個坑點,就是時間,用c++的朋友如果超時的話,小龍人建議把 cin 和 cout 改成scanf 與 printf 試試, 這樣就不會超時了。


代碼實現:
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <map>
#include <cmath>
#include <algorithm>
using namespace std;
const int minnn = 1000001;
const int maxnn = -1000001;
int main()
{
    int t, day, i, j;
    scanf("%d",&t); 
    while( t-- )
    {
        int date[100010];
        int predp[100010] = {0};
        int postdp[100010] = {0};
        scanf("%d",&day);
        for( i=1; i<=day; i++ )
            scanf("%d",&date[i]);
        int minn = minnn, maxn = maxnn;
        for( i=1; i<=day; i++ )
        {
            if( date[i] < minn )                              //找到最小值;
                minn = date[i];
            predp[i] = max(date[i] - minn, predp[i-1]);       //該天前最大收益;
            if( date[day-i+1] > maxn )                        //找到最大值;
                maxn = date[day-i+1];
            postdp[day-i+1] = max(maxn - date[day-i+1], postdp[day-i+2]); //該天后最大收益;
        }

        int max_profit = 0;
        for( i=1; i<=day; i++ )
        {
            max_profit = max(predp[i] + postdp[i], max_profit);  //找出兩次最大收益;
        }
        printf("%d\n",max_profit);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章