1. 程式人生 > >UVA 10003 Cutting Sticks 區間DP

UVA 10003 Cutting Sticks 區間DP

ostream hide min ret 轉移 區間 動態 鍛煉 string

  題目鏈接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=944

  題目大意: 給你一個長度為L的木條, 和N個切割點, 每次切割的代價是當前切割木條的長度, 問最小代價是多少。

  解題思路: 很顯然的區間DP, dp(i, j)表示在i號和j號點之間切割的最小代價。dp轉移方程為dp(i, j) = min(dp(i, k)+dp(k,j)+a[j]-a[i])|k屬於(i, j)  

  代碼:

技術分享
#include <iostream>
#include 
<cstdio> #include <string> #include <vector> #include <map> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map> using namespace std; const int INF = 0x3fffffff;
int dp[100][100]; // d(i, j)在 [i , j] 區間切割的最優費用 int n; int a[100]; int main() { int l; while( ~scanf( "%d", &l ) && l ) { scanf( "%d", &n ); a[0] = 0; a[n+1] = l; for( int i = 1; i <= n; i++ ) { scanf( "%d", &a[i] ); }
for( int i = 0; i <= n+1; i++ ) { for( int j = 0; j <= n+1; j++ ) { dp[i][j] = INF; } } for( int i = 0; i <= n; i++ ) { dp[i][i+1] = 0; } for( int d = 2; d <= n+1; d++ ) { for( int s = 0; s <= n+1; s++ ) { for( int k = s+1; k < s+d; k++ ) { dp[s][s+d] = min( dp[s][s+d], dp[s][k] + dp[k][s+d] + a[s+d] - a[s] ); } } } // for( int i = 0; i <= n+1; i++ ) { // for( int j = 0; j <= n+1; j++ ) { // cout << dp[i][j] << " "; // } // cout << endl; // } printf( "The minimum cutting is %d.\n", dp[0][n+1] ); } return 0; }
View Code

  思考: 這道題本身沒有多難, 但是要註意的地方有很多, 比如說一定要註意轉移的方向, 在算轉移方程的左側的時候一定要保證方程的右側已經算了出來, 就比如說這道題, 想要計算區間(i, j)就必須保證我這個區間內所有只需要切割一下的, 就是說中間隔了一個點的要全部都算出來, 然後才能算隔兩個點的, 隔三個點的.......否則,如果像我一開始想的先枚舉兩個端點, 再枚舉中間點, 就只能那函數做了, 但是我們現在鍛煉的是動態規劃的思維......

UVA 10003 Cutting Sticks 區間DP