1. 程式人生 > >演算法課8-Dynamic Programming⭐️

演算法課8-Dynamic Programming⭐️

動態規劃是常考演算法,將指數級的問題降到多項式級別。

動態規劃和分治法都是將問題劃分成子問題進行求解,它們的區別主要是:

  • 分治法的子問題無重疊
  • 動態規劃的子問題有重疊,並且重疊的個數是指數級別的

動態規劃和貪心法的相同之處是原問題包含子問題的最優解,而它們的區別在於:

  • 貪心法只看區域性最優,最終達到全域性最優
  • 對於動態規劃局部最優不一定是全域性最優

1. Weighted interval scheduling
帶權重的最大相容子集,不能用貪心法進行求解,需要考慮動態規劃的解法。首先將活動按照結束時間排序。兩種情況,一種是選當前的j,那麼最優解等於從後往前找第一個與j不衝突的活動(使用二分查詢加快速度)的opt加上j的權重,一種是不選j,那麼最優解等於j的前一個活動的最優解。如下式:
o

pt(j)=max{vj+opt(p(j)),opt(j1)}opt(j)=max\{v_j+opt(p(j)),opt(j-1)\}
ps.若按照開始時間排序,要反過來找,那麼opt(i)可以定義為,i~n個活動,p(i)是從前往後找第一個不衝突的活動。opt(n+1)=0,return opt(1)。
opt(i)=max{vi+opt(p(i)),opt(i+1)}opt(i)=max\{v_i+opt(p(i)),opt(i+1)\}

2. Segmented least squares


線段擬合點集問題,希望線段儘量少,error儘量小。
error定義為E+cL ,E是平方誤差之和,L是線段條數。
opt(j) 是p1...pjp_1...p_j的最小error,e(i,j)是pi,pi+1...pjp_i,p_{i+1}...p_j的最小平方誤差
opt(j)=min1ij{eij+c+opt(i1)}opt(j)=\min \limits_{1\leq i\leq j}\{e_{ij}+c+opt(i-1)\}
這個演算法的瓶頸在於計算eije_{ij}
,對j要掃一遍,j固定了,i要掃一遍,i固定了,在i j之間要掃一遍, 使得演算法的效率是O(n3)O(n^3).

3. 買賣股票系列

  • 只能買賣一次
    Best Time to Buy and Sell a Stock
    f(j):第j次賣出的最優解, f(1)=0, return max1jn(f(j))\max\limits_{1\leq j\leq n}(f(j)) ,兩種情況,第一種是當天賣出,第二種是前j-1天買入,第j天賣出,第二種情況和第j-1天賣出的區別就是第j天的價格減去第j-1天的價格。
    f(j)=max(0,f(j1)+pjpj1)f(j)=max(0,f(j-1)+p_{j}-p_{j-1})
    一個直觀的想法是說維護到目前為止價格的最低點,用上一行減去下一行即可得到最大利潤。
5 2 7 13 1 9
5 2 2 2 1 1

這道題還可以用分治法做,詳見上一篇博文。

  • 買賣兩次
    Best Time to Buy and Sell Stock III
    設定兩個dp陣列,f1(i)f_1(i)是第i天第一次賣出最大收益,f2(i)f_2(i)是第i天第二次賣出最大收益。
    思路1:
    g1(j)=max1ijf1(i)g_1(j)=\max\limits_{1\leq i \leq j}{f_1(i)} 即為前j天的最大收益
    f2(j)=max1ij{pjpi+g1(i1)}f_2(j)=\max\limits_{1\leq i \leq j}\{p_j-p_i+g_1(i-1)\}
    時間θ(n2)\theta (n^2) 空間θ(n)\theta (n)
    思路2:
    f2(j)=max(g1(j1),f2(j1)+pjpi)f_2(j)=max(g1(j-1),f_2(j-1)+p_j-p_i)
    return max1jn(f2(j))\max\limits_{1\leq j \leq n}(f_2(j))
    時間θ(n)\theta(n) 空間θ(n)\theta(n)

程式碼:

#include <iostream>
using namespace std;

int sale[100005];
int t;
int dp1[100005];
int dp1_max[100005];
int dp2[100005];
int main(){
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&sale[i]); //這裡使用cin會超時
            dp1[i]=0;
            dp2[i]=0;
        }
        int res=0;
        for(int i=1;i<n;i++){
            dp1[i]=max(dp1[i-1]+sale[i]-sale[i-1],0);
            dp1_max[i]=max(dp1_max[i-1],dp1[i]); //最大值儲存別寫錯
            dp2[i]=max(dp1_max[i-1],dp2[i-1]+sale[i]-sale[i-1]);
            res=max(res,dp2[i]);
        }
        cout<<res<<endl;
    }
    return 0;
}
    • dp[i, j] represents the max profit up until prices[j] using at most i transactions.
    • dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] }
      = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj]))
    • dp[0, j] = 0; 0 transactions makes 0 profit
    • dp[i, 0] = 0; if there is only one price data point you can’t make any transaction.

public int maxProfit(int k, int[] prices) {
	int n = prices.length;
	if (n <= 1)
		return 0;
	
	//if k >= n/2, then you can make maximum number of transactions.
	if (k >=  n/2) {
		int maxPro = 0;
		for (int i = 1; i < n; i++) {
			if (prices[i] > prices[i-1])
				maxPro += prices[i] - prices[i-1];
		}
		return maxPro;
	}
	
    int[][] dp = new int[k+1][n];
    for (int i = 1; i <= k; i++) {
    	int localMax = dp[i-1][0] - prices[0];
    	for (int j = 1; j < n; j++) {
    		dp[i][j] = Math.max(dp[i][j-1],  prices[j] + localMax);
    		localMax = Math.max(localMax, dp[i-1][j] - prices[j]);
    	}
    }
    return dp[k][n-1];
}
public int maxProfit(int[] prices) {
		//當前是買入狀態(k<=i天買入,沒賣出)
        int[]hold=new int[prices.length+1];
        int[]sold=new int[prices.length+1];//賣出狀態
        int[]rest=new int[prices.length+1];//冷靜狀態
        hold[0]=Integer.MIN_VALUE;
        sold[0]=0;
        rest[0]=0;
        for(int i=1;i<prices.length+1;i++){
       		//買前需要冷靜
            hold[i]=Math.max(hold[i-1],rest[i-1]-prices[i-1]);
            //賣前需要買
            sold[i]=hold[i-1]+prices[i-1];
            //冷靜期之前要麼是休息要麼是賣掉了
            rest[i]=Math.max(rest[i-1],sold[i-1]);
        }
        return Math.max(rest[prices.length],sold[prices.length]);
    }
public int maxProfit(int[] prices, int fee) {
        if (prices.length <= 1) return 0;
        int days = prices.length, buy[] = new int[days];
        int sell[] = new int[days];
        buy[0]=-prices[0]-fee;
        for (int i = 1; i<days; i++) {
        // keep the same as day i-1, or buy from sell status at day i-1
            buy[i] = Math.max(buy[i - 1], sell[i - 1] - prices[i] - fee); 
        // keep the same as day i-1, or sell from buy status at day i-1
            sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]); 
        }
        return sell[days - 1];
    }

4. 最長遞增子序列
LeetCode Longest increasing subsequence
一個錯誤的思路
dp[i]=max{dp[p(i)]+1,dp[i-1]} 選i或者不選i,如果選,從後往前找到第一個小於i的值的dp值加1,這個思路不對的原因在於,沒辦法保證第一個小於i的值的狀態是選了這個值的狀態,也就是說,可能沒有選這個p(i),它的當前最大值不能保證合法。

  • 思路1
    dp[i]是以i結尾的最長遞增子序列,那麼狀態轉移應該是,從i往前找,比i小的位置j的dp值加1中的最大值,注意,後面的數不一定比前面的大。最後返回的是dp值中最大的那一個。
public int lengthOfLIS(int[] nums) {
        if(nums.length==0) return 0;
        int[]dp=new int[nums.length];
        Arrays.fill(dp,1);
        int result=1;
        for(int i=1;i<nums.length;i++){
            for(int j=i-1;j>=0;j--){
                if(nums[j]<nums[i]){
                   dp[i]=Math.max(dp[i],dp[j]+1);    
                   
                }
            }
            result
            
           

相關推薦

演算法8-Dynamic Programming⭐️

動態規劃是常考演算法,將指數級的問題降到多項式級別。 動態規劃和分治法都是將問題劃分成子問題進行求解,它們的區別主要是: 分治法的子問題無重疊 動態規劃的子問題有重疊,並且重疊的個數是指數級別的 動

漫談演算法 動態規劃 Dynamic Programming

Dynamic Programming一直以來是自己比較弱的一部分,希望可以在這一塊有所提升。 動態規劃,Dynamic Programming。這裡的programming沒有翻譯成程式設計,是因為,這裡的programming的意思是指一個tabular method。其實這也暗示了DP

演算法-動態規劃 Dynamic Programming--從菜鳥到老鳥

個人分類: 演算法 版權宣告:本文為博主原創文章,轉載請標明出處。 https://blog.csdn.net/u013309870/article/details/75193592 前言 最近在牛客網上做了幾套公司的真題,發現有關動態規劃(Dynamic Programming)演算

演算法-動態規劃 Dynamic Programming--從菜鳥到老鳥

前言 最近在牛客網上做了幾套公司的真題,發現有關動態規劃(Dynamic Programming)演算法的題目很多。相對於我來說,演算法裡面遇到的問題裡面感覺最難的也就是動態規劃(Dynamic Programming)演算法了,於是花了好長時間,查找了相關

Dynamic Programming中的 Bellman-Ford演算法

Shortest Paths with negative weights Dynamic Programming Pseudocode // Shortest paths with negative edges Shortest-Path(G, t) {

一文弄懂動態規劃(DP Dynamic Programming)下樓梯,國王和金礦,揹包問題,Dijkstra演算法

動態規劃 參考連結 漫畫演算法,什麼是動態規劃? DP 動態規劃是一種分階段求解決策問題的數學思想 題目一 問:下樓梯問題,有一座高度是10級臺階的樓梯,從下往上走,每跨一步只能向上1級或者2級臺階,請問有多少中走法。 思路 剛才這個題目,你每走一步就有兩

coursera演算法 Programming Assignment 1:Percolation

這次演算法作業的任務是通過蒙特卡洛模擬來計算 percolation threshold即滲濾閾值。 滲濾:percolation滲濾是一個由絕緣體和金屬隨機分佈的複雜系統。那麼它的金屬分佈在什麼情況下會導致它是一個導體。科學家定義了一個抽象的被稱作perco

演算法初探-動態規劃(Dynamic Programming)

程式設計之中接觸到很多關於演算法的知識,想來整理一番,算是對自己記憶的一個提醒 1.Coin11Problem  問題為:使用最少的三種面值為1,3,5的硬幣組合出11元。 重要的是狀態以及狀態轉移方程 d(i)=min{ d(i-vj)+1 },其中i-vj >

演算法:解碼方法(動態規劃)—— decode-ways(Dynamic programming)

problem:A string “s” is consisted of number characters. If thesubstring value of one or two adjacent characters in “s” is between 1 and 26

公司聚會喜歡程度計算 演算法(動態規劃)Dynamic Programming

問題:      Professor Stewart is consulting for the president of a corporation that is planning a company party. The company has a hierarchi

五大常見演算法策略之——動態規劃策略(Dynamic Programming

Dynamic Programming   Dynamic Programming是五大常用演算法策略之一,簡稱DP,譯作中文是“動態規劃”,可就是這個聽起來高大上的翻譯坑苦了無數人,因為看完這個演算法你可能會覺得和動態規劃根本沒太大關係,它對“動態”和“規劃”都沒有太深的體現。   舉個最簡單的例子去先淺顯

HDU 4972 A simple dynamic programming problem

als pos trac article 隨機 simple mat abs ble 隨機輸出保平安 #include <cstdio> #include <cmath> #include <iostream> #inc

2017 UESTC Training for Dynamic Programming

輪廓 multi eof complete ons 球隊 tags clu puts 2017 UESTC Training for Dynamic Programming A 思維, 或 dp, 很有意思 方法1: 構造法:蛇形安排賽程表算法復雜度:O(N

Dynamic Programming

int rom enc sequence expr common condition dep tro First, think of solution as a linear sequence of decisions. Second, work backward from

以計算斐波那契數列為例說說動態規劃算法(Dynamic Programming Algorithm Overlapping subproblems Optimal substructure Memoization Tabulation)

ash 麻省理工學院 遞歸樹 經典 top 有關 ctu dynamic 代碼 動態規劃(Dynamic Programming)是求解決策過程(decision process)最優化的數學方法。它的名字和動態沒有關系,是Richard Bellman為了唬人而取的。

[leetcode]Dynamic Programming-121. Best Time to Buy and Sell Stock

ram tran input output algorithm ice dynamic c program one Say you have an array for which the ith element is the price of a given stock o

Dynamic programming language

cost system eat could compute imp with ffi behaviors 動態改變運行時結構 Dynamic programming language, in computer science, is a class of high-leve

動態規劃(dynamic programming

program 選擇 因此 移動 開始 解決 特征 尋找 ima 1、動態規劃是通過組合字問題的解而解決整個問題的。 2、它與分治法的區別:     分治法是將問題分解為一些獨立的子問題,遞歸的求解各個子問題,然後合並子問題的解而得到源問題的解。     而動態規劃適合用於

動態規劃(dynamic programming)(二、最優子問題與重疊子問題,以及與貪心的區別)

貪心策略 找到 算法 找問題 貪心 模式 解決 策略 最優 一、動態規劃基礎   雖然我們在(一)中討論過動態規劃的裝配線問題,但是究竟什麽時候使用動態規劃?那麽我們就要清楚動態規劃方法的最優化問題中的兩個要素:最優子結構和重疊子問題。   1、最優子結構     1)如果

2018.3.1-2 huffman code and dynamic programming

可能 空間 blog 線圖 bottom div 多重 很多 基礎 這周先是huffman code,這東西是一種對數據進行二進制編碼的方式,這樣子編碼可以壓縮空間,算是一種壓縮算法。比如一串數據裏只有a,b,c,d四個字節,一般可能會覺得就00,01,10,11來指代這四