1. 程式人生 > >51nod 1021 石子歸併 (動態規劃 簡單程式碼)

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]表示前i個石子的價值,sum[j] - sum[i-1]即合成兩堆石子((第i到第k合併出的石子),(第k+1到第j合併出的石子))。

但是考慮要求1-4,

需要先求出(1-1,2-4),(1-2,3-4),(1-3,4-4)。

所以我們不能直接按橫縱座標遍歷。

需要換一種遍歷方式,在紙上畫一畫就可以知道有哪些可行的遍歷方式了。

我的遍歷方式是
這裡寫圖片描述

從左往右看,對角線全是0,表示合併(i,i)的代價是0。

這種遍歷方式能夠保證遍歷是按照邏輯上的順序的。

程式碼:

#include <iostream>
using namespace std;
typedef long long ll;
#define INF 2147483647

//輸入 
int n;
int a[110];            

int dp[110][110];//dp[i][j]表示第i到第j堆石子合成所需的最小代價   
int sum[110];    //字首和 

int main(){
    cin >> n;
    for(int
i = 1;i <= n; i++) cin >> a[i], sum[i] = sum[i-1] + a[i]; int ans = 0; for(int i = 1;i <= n-1; i++){ //(x,y)表示圖上每一個箭頭的起點 int x = i;int y = i+1; //開始往上走(箭頭方向) while(x >= 1){ dp[x][y] = 2000000000; for(int j = x;j <= y-1; j++){ dp[x][y] = min(dp[x][y],dp[x][j] + dp[j+1
][y] + sum[y] - sum[x-1]); } x--; } } cout << dp[1][n] << endl; return 0; }