d686: 10003 - Cutting Sticks

Tags: dp


出處:https://zerojudge.tw/ShowProblem?problemid=d686
提交:https://zerojudge.tw/Submissions?problemid=d686&account=allllllan123456


問題:給定一根長度為 $L\in[1,1000]$ 的木棍,以及 $N\in[0,49]$ 個欲切割點 $C_i\in[1,L-1]$,定義每切一刀的成本就是該子木棍在切割之前當下的長度,請問怎樣的切割順序才能有最小的總切割成本?


解法:這題是聖經本 Introduction to Algorithms 第三版裡面第 15.1 的經典章節。對於一根有 n 個可切割點 cut[1:n] 的木棍 (注意 cut[0] 與 cut[n+1] 是為端點),我們想從中挑一個最好的切割點 j,使得對 A[1:j] 作切割的成本 X 與對 A[j:n] 作切割的成本 Y 之總和 X + Y 要最小。和 c112 不同,因為無論以誰為切割點,整根木棍的長度成本都會算進去,所以它不會成為選擇的理由。另外,因為每個子問題都會被檢查到,所以這題其實可以使用 bottom up 的 DP。


 1#include <bits/stdc++.h>
 2using namespace std;
 3
 4int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); // IO 優化
 5    int L, N, cost[52][52], cut[52];
 6    for (int i=0; i<=50; i++) cost[i][i+1] = 0;
 7    while (cin>>L && L) { cin >> N; cut[0] = 0;
 8        for (int i=1; i<=N; i++) cin >> cut[i];
 9        cut[N+1] = L;
10        for (int d=2; d<=N+1; d++)
11            for (int i=0; i+d<=N+1; i++) {
12                cost[i][i+d] = INT_MAX;
13                for (int j=i+1; j<i+d; j++) {
14                    int temp = cost[i][j] + cost[j][i+d];
15                    if (temp < cost[i][i+d]) cost[i][i+d] = temp;
16                }
17                cost[i][i+d] += cut[i+d] - cut[i];
18            }
19        cout << "The minimum cutting is " << cost[0][N+1] << ".\n";
20    }
21    return 0;
22}

no image