一條直線上擺放著一行共n堆的石子。現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請編輯計算出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。
輸入有多組測試資料。
每組第一行為n(n<=100),表示有n堆石子。
二行為n個用空格隔開的整數,依次表示這n堆石子的石子數量ai(0每組測試資料輸出有一行。輸出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。 中間用空格分開。
1 2 3
9 11
乙個經典的dp題目,我們用 min_cost [ i ] [ j ] 表示將第 i 堆石子和第 j 堆石子合併後的最小消耗,當然我們知道只有鄰接的兩個石子堆可以合併,所以我們求 min_cost [ i ] [ j ] 的時候,需要求出 min_cost [ i ] [ k ] 和 min_cost [ k , j ] ,而為了求出 min_cost [ i ] [ k ] , 我們需要求 min_cost [ i ] [ t ] 和 min_cost [ t ] [ k ] .....
這就是很明顯的乙個dp了,先從區間長度為1的區間開始,列舉每乙個區間,然後從區間長度為2的區間開始,列舉每乙個結點,依此類推......最後我們就得到了 min_cost [ 1 ] [ n ] ,max_cost [ 1 ] [ n ] 同理。
我們需要注意合併兩個區間的時候不僅需要讓原來兩個子區間的值相加,而且這兩個區間中的元素的值和也需要加上,所以轉移方程為:
min_cost[i][i + k] = min(min_cost[i][i + k], min_cost[i][j] + min_cost[j + 1][i + k] + sum[i + k] - sum[i - 1]);
( k 代表區間長度,i 代表起點, j 代表所求區間 [ i ] [ i + k ] 的子區間的分界點,sum [ x] 代表字首和)
#include#include#include#include#include#include#include#include using namespace std;
typedef long long ll;
const int max = 1e3 + 10;
const int inf = 0x3f3f3f3f;
using namespace std;
int num[max];
int min_cost[max][max]; //把第i堆石子和第j堆石子合併的最小花費
int max_cost[max][max]; //把第i堆石子和第j堆石子合併的最大花費
int sum[max]; //字首和
int main()
for (int i = 1; i <= n; i++)
for (int k = 1; k <= n - 1; k++) //更新的區間長度
}} cout << min_cost[1][n] << " " << max_cost[1][n] << endl;
} return 0;
}
282 石子合併
設有n堆石子排成一排,其編號為1,2,3,n。每堆石子有一定的質量,可以用乙個整數來描述,現在要將這n堆石子合併成為一堆。每次只能合併相鄰的兩堆,合併的代價為這兩堆石子的質量之和,合併後與這兩堆石子相鄰的石子將和新堆相鄰,合併時由於選擇的順序不同,合併的總代價也不相同。例如有4堆石子分別為 1 3 ...
2298 石子合併
2008年省隊選拔賽山東 時間限制 1 s 空間限制 256000 kb 題目等級 gold 在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。輸入描...
3 3 石子合併問題
問題描述 在乙個圓形操場的四周擺放著 n 堆石子。現要將石子有次序地合併成一堆。規定每次只 能選相鄰的 2 堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計一 個演算法,計算出將 n 堆石子合併成一堆的最小得分和最大得分。程式設計任務 對於給定 n 堆石子,程式設計計算合併成一堆的...