1. 程式人生 > >環形石子合併問題(動態規劃)(洛谷P1880)

環形石子合併問題(動態規劃)(洛谷P1880)

                    環形石子合併問題(動態規劃)

傳統的石子合併問題為:有N堆石子,現要將石子有序的合併成一堆,規定如下:每次只能移動相鄰的2堆石子合併,合併花費為新合成的一堆石子的數量,求將這N堆石子合併成一堆的總花費最小(或最大)。

這類問題類似區間DP的解法,設dp[i][j]為合併從i到j的最小總花費,那麼預處理出字首和,轉移方程為dp[i][j]=max(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]),且i==j時dp[i][j]=0;核心程式碼為:

    for(int v = 1; v < n; v++)
    {
        for(int i = 0;i < n-v; i++)
        {
            int j = i + v;
            dp[i][j] = INF;
            int tmp = sum[j] - (i > 0 ? sum[i-1]:0);
            for(int k = i; k < j; k++)
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + tmp);
        }
    }

環形石子合併問題為洛谷P1880

題目描述

在一個圓形操場的四周擺放N堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。

試設計出1個演算法,計算出將N堆石子合併成1堆的最小得分和最大得分.

輸入輸出格式

輸入格式:

資料的第1行試正整數N,1≤N≤100,表示有N堆石子.第2行有N個數,分別表示每堆石子的個數.

輸出格式:

輸出共2行,第1行為最小得分,第2行為最大得分.

輸入輸出樣例

輸入樣例#1: 
4
4 5 9 4
輸出樣例#1: 
43
54

題解:對於環形的處理典型的方法是將環拆成鏈,也就是將長度擴大2倍,求鏈的最佳得分可以通過反向列舉左端點,然後找到當前到右端點的最佳,因為鏈的長度為原來的兩倍,所以應該從2*n-1列舉,每次列舉n的長度,然後從1-n找最後的答案即可。

AC程式碼:

#include <iostream>
#include <algorithm>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 507;
const int inf = 0x3f3f3f;
int n,m,a[maxn],sum[maxn],dp_max[maxn][maxn],dp_min[maxn][maxn];
int main(int argc, char const *argv[])
{
    cin>>n;
    _for(i,1,n)
    {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    _for(i,n+1,n*2)
    {
        a[i]=a[i-n];
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=n*2-1;i>0;i--)
    {
        _for(j,i+1,i+n)
        {   
            dp_min[i][j]=inf;
            _for(k,i,j-1)
            {
                dp_min[i][j]=min(dp_min[i][j],dp_min[i][k]+dp_min[k+1][j]+sum[j]-sum[i-1]);
                dp_max[i][j]=max(dp_max[i][j],dp_max[i][k]+dp_max[k+1][j]+sum[j]-sum[i-1]);
            }
        }
    }
    int ans_min = inf;
    int ans_max = 0;
    _for(i,1,n)
    {
        ans_max=max(dp_max[i][i+n-1],ans_max);
        ans_min=min(dp_min[i][i+n-1],ans_min);
    }
    cout<<ans_min<<endl;
    cout<<ans_max<<endl;
    return 0;
}

相關推薦

環形石子合併問題動態規劃P1880

                    環形石子合併問題(動態規劃)傳統的石子合併問題為:有N堆石子,現要將石子有序的合併成一堆,規定如下:每次只能移動相鄰的2堆石子合併,合併花費為新合成的一堆石子的數量,求將這N堆石子合併成一堆的總花費最小(或最大)。這類問題類似區間DP的

2018牛客多校第九場E動態規劃,思維,取模

pac namespace for ons mod 思維 space scan 動態規劃 #include<bits/stdc++.h>using namespace std;const long long mod=1000000007,inv=57000000

2017烏魯木齊區域賽A動態規劃,組合數學,期望

ble set 可能 組合 name main i++ return soft #include<bits/stdc++.h>using namespace std;double c[110][110];double g[110];double dp[110]

【BZOJ4006】管道連接動態規劃,斯坦納樹

map 動態 code ring class new get efi include 題面 BZOJ 洛谷 題解 和這題區別不是很大吧。 基本上拿過來改一下就做完了。 #include<iostream> #include<cstdio> #incl

Vijos P1133 裝箱問題動態規劃,01揹包,NOIP

noip2001普及組第四題 樣例分析 輸入容積24,6件物品 因為容量最多可達20000,為節省空間,只用一維陣列,用f[j]表示在容積為j時所裝物品所佔用的最大體積 對每一件物品,有放或不放兩種策略,不放,則體積仍為之前的f[j];放,則須留有足夠的空間,並佔用一定的體積,即f[j-v]+v 為了保

劍指offer(47):禮物的最大值動態規劃詳解,python版

本部落格主要內容為圖書《劍指offer》第二版47 題的解題思路及程式碼。方法可能還有不足之處,歡迎大家討論評論。 1. 題目描述   在一個 m*n 的棋盤中的每一個格都放一個禮物,每個禮物都有一定的價值(價值大於0).你可以從棋盤的左上角開始

【BZOJ1492】【NOI2007】貨幣兌換動態規劃,CDQ分治,Splay

題面 BZOJ 洛谷 Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下 簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個實數。每天隨著市場的起伏波

hdu1024HDU 1024 Max Sum Plus Plus動態規劃 很詳很詳解

Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6725    Ac

【BZOJ5469】[FJOI2018]領導集團問題動態規劃,線段樹合並

狀態 space 位置 ret max flag 得到 modify 線段樹合並 【BZOJ5469】[FJOI2018]領導集團問題(動態規劃,線段樹合並)  題面 BZOJ 洛谷 題解 題目就是讓你在樹上找一個最大的點集,使得兩個點如果存在祖先關系,那麽就要滿足祖先的權

合併石子動態規劃經典題

步驟: 1. 設狀態:f[i][j]表示從第i堆合併到第j堆,合併成一堆的最小得分 2. 初始狀態:f[i][i]=0;     最終狀態:f[1][n];//從第1堆合併到第n堆的最小得分 3.狀態轉移方程:f[i][j]=max(f[i][j],f[i][k]+f[k+

BZOJ4919 大根堆動態規劃+線段樹合併/treap+啟發式合併

  一個顯然的dp是設f[i][j]為i子樹內權值<=j時的答案,則f[i][j]=Σf[son][j],f[i][a[i]~n]++。這樣是可以線段樹合併的,將各兒子加起來然後打上加法標記即可。需要標記永久化。   另一種做法是考慮擴充套件經典的單調佇列優化LIS的做法,維護子樹內答案為k時最小的最

51nod1021 石子歸併動態規劃

簡單模板題 #include<iostream> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int INF=1e9+7; i

Vijos P1218 數字遊戲動態規劃環形DP

丁丁最近沉迷於一個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數(一共n個),你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到一個數k。遊戲的要求是使你所得的k最大或

51nod 1021 石子歸併 動態規劃 簡單程式碼

題目: 思路:動態規劃,遞推式子 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);    dp[i][j]表示合併第i到第j個石子需要的最少代價。sum[i]表

hud2059龜兔賽跑動態規劃

n+1 動物 include output script text sam 起跑線 other 龜兔賽跑 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T

ship動態規劃

動態規劃 輸出 一個 子序列 升序 端點 如果 2個 長度 (ships.pas/c/cpp) 來源:《奧賽經典》(提高篇)【問題描述】PALMIA國家被一條河流分成南北兩岸, 南北兩岸上各有N個村莊。 北岸的每一個村莊有一個唯一的朋友在南岸,且他們的朋友村莊彼此不同。每一

計蒜客--爬樓梯 動態規劃

tle nbsp vector main long 3.1 false n) 方法 假設你現在正在爬樓梯,樓梯有 nn 級。每次你只能爬 11 級或者 22 級,那麽你有多少種方法爬到樓梯的頂部? 輸入格式 第一行輸入一個整數 n(1\leq n \leq 50)n

動態三角形動態規劃思想入門

star ber name 做到 tar triangle 解決 算法 log 個人心得:動態規劃是一種隸屬於決策學的一個算法思想,他能夠很好的解決多階段決策問題,這種思想對於我們的生活還是科研都是必不可少的, 需要好生體會,學會動態方程的轉移,做到具體問題具體分析。 那這

【算法學習】雙調歐幾裏得旅行商問題動態規劃(轉)

png .com 16px 我們 pan 子結構 最小 而且 復雜度 雙調歐幾裏得旅行商問題是一個經典動態規劃問題。《算法導論(第二版)》思考題15-1和北京大學OJ2677都出現了這個題目。 旅行商問題描述:平面上n個點,確定一條連接各點的最短閉合旅程。這個解的一般形式