NOIP 石子合併

2021-10-04 18:21:29 字數 2023 閱讀 6893

題目

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

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

輸入格式

資料的第 1 行是正整數 n表示有n 堆石子。

第 2 行有 n 個整數,第 i 個整數 a_i表示第 i 堆石子的個數。

輸出格式

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

輸入 #1 複製

44 5 9 4

輸出 #1 複製

4354

這類dp題, 題目說的是:

可以從左到右順序每次合併前兩堆, 也可以 左邊的合成一堆,右邊的合成一堆,最後合併這兩個大堆。

我們需要用到的,就是後面這種,這種用來求 最大,最小 都可以。

1:這種dp,稱為,區間dp,乙個大的分成左右兩個區間,左右區間裡 又分 左右區間。。。。。。。

小區間問題解決了,大的也就能解決了。

2:先做預處理,把各種堆的資料先算好 cost【l】【r】(l—r 堆這間的合)

轉移方程:求最小: dp1[l][r] = min(dp1[l][r],dp1[l][k]+dp1[k+1][r]+cost[l][r]); (左區間 + 右區間 + 總的合)

求最大也是一樣。

注意:這是題目說的是 圍成一圈,所以是環形的, 我們需要開兩倍n,相當於把n個 複製一遍,排成1–n ,1—n模擬環形

ps:如果不太懂,可以先把問題簡單化,比如:取消迴圈條件, 而且只求 最小得分。

** 下面寫了這個簡單的問題。如果不懂可以先弄懂簡單的。

#include

using

namespace std;

#include

int n;

//因為是迴圈,所以陣列都要開兩倍

int w[

205]

;//每堆石子的原重量。

int dp1[

205]

[205];

//做最小得分

int dp2[

205]

[205];

//做最大得分

int cost[

205]

[205];

//cost[i][j] 表示 第i--j堆 的石子的總重量

intmain()

// memset(dp1,1e6,sizeof(dp1)); //因為要求最小,先給初值,

// 求最大的就不需要額,

for(

int i=

1;i<=n*

2;i++)}

}for

(int i=

1;i<=n;i++

)for

(int len=

1;len}int ans1 =

1e8,ans2=0;

for(

int i=

1;i<=n;i++

) cout

}//問題簡化下。取消迴圈條件, 求最小得分

//#include

//using namespace std;

//#include

//int n;

//int w[105]; //每堆石子的原重量。

//int dp[105][105]; //做dp

//int cost[105][105]; //cost[i][j] 表示 第i--j堆 的石子的總重量

//int main()

// memset(dp,1e6,sizeof(dp));

// for(int i=1;i<=n;i++)

// }

// }

// for(int i=1;i<=n;i++)

// for(int len=2;len<=n;len++)

// }

// }

// cout//}

石子合併問題

在乙個圓形操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。分析 假設有n堆石子需要合併,可以設計乙個2 n 1個元素的陣列來儲存每堆石子的個數。...

石子合併問題

在乙個圓形操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。沒有用dp 感覺一般的也能寫,時間複雜度也不高。include include inc...

石子合併問題

石子合併問題是最經典的dp問題。首先它有如下3種題型 1 有n堆石子,現要將石子有序的合併成一堆,規定如下 每次只能移動任意的2堆石子合併,合併花費為新合成的一堆石子的數量。求將這n堆石子合併成一堆的總花費最小 或最大 分析 當然這種情況是最簡單的情況,合併的是任意兩堆,直接貪心即可,每次選擇最小的...