1. 程式人生 > >HDU3480_區間DP平行四邊形優化

HDU3480_區間DP平行四邊形優化

做到現在能一眼看出來是區間DP的問題了

也能夠知道dp[i][j]表示前  i  個節點被分為  j  個區間所取得的最優值的情況

cost[i][j]表示從i到j元素區間中的值,這裡可以直接排序後簡單求出——也就是我們的代價函式

這樣其實就能夠做出來了,但是空間複雜度是n3入門的題能過,普通點的都會考察你一下斜率DP的優化和四邊形不等式的優化。目前我主要就懂了平行四邊形的優化

首先你要確保dp和cost這兩個都滿足四邊形不等式這個前面有過證明的部落格這裡就簡單一提。

(部落格園真的好棒,自動儲存的,剛剛不小心全關了...)

( a < b <= c< d )

f[a][c]+f[b][d]<=f[b][c]+f[a][d]

這類不等式的滿足就可以證明出決策函式s[i][j]滿足上一等式——————決策函式s[i][j]表示dp[i][j]取得最優值時的k值,也就是把前 i 個分成 j 個區間 化為前 k 個分為 j - 1個區間留下一個區間 k +1  --- i這類問題,最優值k取s[i][j]

所以這個不等式就可以利用DP的層層遞推性,來縮小k的遍歷範圍如下

i< i+1<=j< j+1

那麼我                   s[i][j-1]<=s[i][j]<=s[i+1][j]

所以對於我們的遍歷j應該是正序的i應該是逆序的這樣才能層層推嘛,對於決策函式的初始化

s[i][i] = i前i個分成i段的最優值怎麼分都可以但是為了縮小範圍所以取  i  更合適

s[i][1]  吧前i個元素,分成1個區間那麼k的取值就是0呢

s[n+1][j] n + 1是 i越界的情況,可以看上面的決策函式的不等式,i+1是完全有越界的情況出現的,所以對於越界的情況我們統一賦值n也就是k的最大取值了

做了這種處理之後,剩下的就ojbk了,加油

這些東西昨天怎麼想都想不出來,睡了一家,今天路上一想就通了,好不奇怪,所以不要太心急,追求效率是應該的但也要追求記憶時間額的效率呢,加油ACMer!

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define inf (1 << 30)
using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 5e3 + 10;
int dp[maxn][maxm];
//dp[i][j]把前i個數分為j個集合所得到的最優值
int s[maxn][maxm];
//dp[i][j]的前面的狀態
int a[maxn];
void init()
{
    memset(dp,0,sizeof(dp));
    memset(s,0,sizeof(s));
}
int getval(int l,int r)
{
    return (a[r] - a[l]) * (a[r] - a[l]);
}
int main()
{
    int t,n,m;
    scanf("%d",&t);
    int cas = 0;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+n);
        //用s[i][j]表示dp[i][j]取得最優解的時候k的位置的話
        //用s[i][j]來表示選dp[i][j]的最佳選擇然後s[i-1][j]<=s[i][j]<=s[i][j+1]

        for(int i = 1;i <= n;i++)
        {
            dp[i][1] = getval(1,i);
            dp[i][i] = 0;
            s[i][i] = i;
            s[i][1] = 0;
        }

        for(int j = 2;j <= m;j++)
        {
            s[n+1][j] = n ;//越界情況
            for(int i = n;i >= j;i--)
            {
                dp[i][j] = inf;
                for(int k = s[i][j-1];k <= s[i+1][j];k++)
                {
                    if(dp[i][j] > dp[k][j-1] + getval(k+1,i))
                    {
                        dp[i][j] = dp[k][j-1] + getval(k+1,i);
                        s[i][j] = k;
                    }
                }
            }
        }
        printf("Case %d: %d\n",++cas,dp[n][m]);
    }
    return 0;
}

 嗯嗯自己寫的吧,演算法有很大的優化空間,時間消耗過大,險過

而且空間佔用很大,就模擬大佬的程式碼學習了一下滾動陣列,優化空間

空間消耗過大,滾動陣列
滾動陣列一般在DP題和狀態壓縮演算法方面用的多,而且優化後效率很高,推薦使用。
對什麼可以滾動呢??
一共就兩個東西,一個是分為區間數,一個是元素的個數、
咋一眼也就知道分的區間數應該是能滾動的,元素個數沒什麼好的想法
說明白一點,先看看原來沒有滾動的版本
dp[i][j] > dp[k][j-1] + getval(k+1,i)
i是元素個數的限制
j是分的區間個數的限制
你看到k是要遍歷的,也就是元素個數是不能壓縮的,滾動陣列要具備的條件就是,他一次
只用部分值,很少一部分,然後我們可以滾動儲存
所以看看j,劃分的區間個數,在進行更新時好像只和j-1有關呢
哈哈,空間為2的滾動陣列出來了

#include <cstdio>
#include <string.h>
#include <algorithm>
#include <iostream>
#define inf (1<<30)
using namespace std;

const int maxn = 1e4 +10;
const int maxm = 1e3 + 10;
int dp[2][maxn];//這裡問題不一樣了第一維是分的區間個數,第二維是元素個數

int s[2][maxn];
int a[maxn];

int n,m;

void init()
{
    for(int i = 1;i <= n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);

    for(int i = 1;i <= n;i++)
    {
        dp[1%2][i] = (a[i] - a[1]) * (a[i] - a[1]);
        s[1%2][i] = 0;
    }
}
void solve()
{
    for(int i = 2;i <= m;i++)
    {
        s[i%2][n+1] = n;
        for(int j = n;j > i;j--)
        {
            dp[i % 2][j] = inf;
            for(int k = s[(i-1)%2][j];k <= s[i%2][j+1];k++)
            {
                if(dp[(i-1) % 2][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]) < dp[i%2][j])
                {
                    dp[i%2][j] = dp[(i-1) % 2][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]);
                    s[i % 2][j] = k;
                }
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int ca = 1; ca <= t;ca++)
    {
        scanf("%d%d",&n,&m);
        init();
        solve();
        printf("Case %d: %d\n",ca,dp[m%2][n]);
    }
    return 0;
}

 然後大佬的演算法時間消耗也少,真的是很不錯,而且dp的維度徵好和我的相反

相關推薦

HDU3480_區間DP平行四邊形優化

做到現在能一眼看出來是區間DP的問題了 也能夠知道dp[i][j]表示前  i  個節點被分為  j  個區間所取得的最優值的情況 cost[i][j]表示從i到j元素區間中的值,這裡可以直接排序後簡單求出——也就是我們的代價函式 這樣其實就能夠做出來了,但是空間複

藍橋杯/nyoj 737 合併石子 區間dp+平行四邊形優化

問題描述   在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。 輸入格式   輸入第一行包含一個整數n,表示石子的堆數。   接下來一行,包含n個整數,按

區間dp四邊形不等式優化 學習筆記

部落格目錄 很久之前在網上看了傳說中的四邊形不等式,然後現在發現忘光了。趁比賽前夕趕快拿來熟悉一下。 一、引入 形如: dp[i][j]=min{dp[i][k]+dp[k+1][j]+cost[i][j]} 的狀態轉移方程,如果不加優化的話ijk三層迴圈O(n

DP平行四邊形優化

Luogu P4767 [IOI2000]郵局 #include <bits/stdc++.h> using namespace std; int n,m,a[3005],mk[3005][

區間動態規劃——平行四邊形優化

區間動態規劃:   針對區間問題的最優解而產生的一種動態規劃演算法,通常以區間為狀態來記錄最優解,故狀態為O(N^2)   而轉移則是列舉這段區間中的決策點,通過兩個更小的區間最優解得合併來得到這段區間的狀態,故轉移為(N)   則狀態O(N^2),轉移O(N),總時間

用一題來說明dp平行四邊優化

poj 1160  題意:給出n個村莊,村莊是一條直線排好的,並且給出每個村莊到直線最左邊初始點的距離。現在要建立m個郵局,於是引入一個距離S{各個村莊到最近的郵局的距離和}。那麼現在問題來了如何使得這個S的值最小? 題解:定義這樣的方程 dp[i][j] = min{ d

51Nod 1022 石子歸並 V2(區間DP+四邊形優化

增加 pre 分享 ems 滿足 log 如果 算法 技術 題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 題目大意: N堆石子擺成一個環。現要將石子有次序地合並成一堆。規定

Hdu 3516 tree construction(區間DP四邊形優化)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=3516 題意:給出n個點,後一個點在前一個點的右下方,然後用直線沿著座標軸將這些點連線起來,問最短的距離是多少。 思路:首先是用區間DP來列出狀態轉移方程,我列出來的方程是dp[i][j]=m

平行四邊形不等式優化DP——筆記

推很久推出方程後發現時間複雜度太大 TLE是不是很沮喪 優化方式及限定條件 來道例題 Post Office There is a straight highway with villages alongside the highway. The highway is r

平行四邊形不等式優化DP

一.前言 DP一直是程式設計中的一個難題,解決它不僅需要大量刷題,還需要學會各種DP的方法。這裡,我就主要講一個DP的優化方法:平行四邊形不等式優化DP動態規劃。(好難呀)     二.平行四邊形不等式是個啥? 1.題目引入:猴子派對 遠離我們的世界,

區間dp+四邊形不等式優化

mes 取數 列數 scan 自己 min oid 表示 \n 區間dp+四邊形優化 luogu:p2858 題意 給出一列數 \(v_i\),每天只能取兩端的數,第 j 天取數價值為\(v_i \times j\),最大價值?? 轉移方程 dp[i][j] :n天賣掉i.

石子歸併(區間dp & 四邊形不等式優化

基準時間限制:1 秒 空間限制:131072 KB 分值: 20 難度:3級演算法題  收藏  取消關注 N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能

51nod oj 1022 石子歸併 V2 【環形區間DP----四邊形不等式優化

題目傳送門:1022 四邊形不等式優化: m[i,j]=min{m[i,k]+m[k,j]}(s[i,j-1]≤k≤s[i+1,j]) 當m[i,j]=min{m[i,k]+m[k,j]}(i≤

【轉】斜率優化DP四邊形不等式優化DP整理

dex add ive mat 整理 off code 斜率dp 好的 當dp的狀態轉移方程dp[i]的狀態i需要從前面(0~i-1)個狀態找出最優子決策做轉移時 我們常常需要雙重循環 (一重循環跑狀態 i,一重循環跑 i 的所有子狀態)這樣的時間復雜度是O(N^2)而 斜

學習筆記第十七節:斜率優化Dp四邊形不等式證明決策單調

正題       我就以這一題:玩具裝箱裝玩具來引入我們今天的話題。       我們先設f[i]表示前i個玩具裝的最小費用是多少。       那麼,很明顯就有我們列舉一個j,使得j+1到i裝

演算法講解 -- 區間dp經典模型與優化(石子歸併)

石子合併問題是最經典的DP問題。首先它有如下3種題型: PPT講解:點選開啟連結 (1)有N堆石子,現要將石子有序的合併成一堆,規定如下:每次只能移動任意的2堆石子合併,合併花費為新合成的一堆石子的數量。求將這N堆石子合併成一堆的總花費最小(或最大)。   分析:當然這種情

Codeforces 958C2 Encryption (medium) (區間dp優化)(*2100)

https://codeforces.com/contest/958/problem/C2 這道題是明顯的區間dp,我們跑三重for迴圈,模擬S的長度從1-n,分成的區間數(1-k),用二維陣列dp[n][k]表示 狀態轉移方程   f[i][j]=max(f[k][j−1]+

【總結】從詩人小G談DP四邊形不等式優化

四邊形不等式 設w(x,y)w(x,y)w(x,y)是定義在整數集合上的二元函式。若對於定義域上的任何整數,a,b,c,d(a≤b≤c≤d)a,b,c,d(a\leq b\leq c\leq d)a

bzoj1563(dp四邊形不等式優化

Description Input Output 對於每組資料,若最小的不協排程不超過1018,則第一行一個數表示不協排程若最小的不協排程超過1018,則輸出”Too hard to arrange”(不包含引號)。每個輸

[dp專題-四邊形不等式優化]51nod 1022

1021石子歸併 V1N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將N堆石子合併成一堆的最小代價。 例如: 1 2 3 4,有不少合併方法 1 2 3 4 => 3 3 4(3)