題目
在乙個圓形操場的四周擺放 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堆石子合併成一堆的總花費最小 或最大 分析 當然這種情況是最簡單的情況,合併的是任意兩堆,直接貪心即可,每次選擇最小的...