做者:jostree 轉載請註明出處 http://www.cnblogs.com/jostree/p/4098562.htmlphp
題目連接:print neatly 整齊打印 算法導論html
考慮在一個打印機上整齊地打印一段文章的問題。輸入的正文是$n$個長度分別爲$L_1,L_2,\dots ,L_n$(以字符個數度量)的單詞構成的序列。咱們但願將這個段落在一些行上整齊地打印出來,每行至多$M$個字符。「整齊度」的標準以下:若是某一行包含從i到j的單詞$(i<j)$,且單詞之間只留一個空格,則在行末多餘的空格字符個數爲 $M - (j-i) - (L_i+ \cdots + L_j)$,它必須是非負值才能讓該行容納這些單詞。咱們但願全部行(除最後一行)的行末多餘空格字符個數的立方和最小。請給出一個動態規劃的算法,來在打印機整齊地打印一段又$n$個單詞的文章。分析所給算法的執行時間和空間需求。ios
使用動態規劃算法,$dp[i]$表示從第一個單詞到第$i$個單詞所須要的最小代價。對於每個單詞分別考慮本身單獨一行,和前一個單獨佔據一行$\ldots$ 和前$k$個單詞佔據一行的狀況,其中從$k$到$i$的字符串長度不超過每行最多所能容納的字符串長度$m$,最後從後向前遍歷$dp$數組,計算分別把最後的$k$個單詞做爲最後一行,且不計算代價的狀況下最小的代價。算法
代碼以下:數組
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <cstring> 5 #include <algorithm> 6 #include <limits.h> 7 #define MAXN 2010 8 using namespace std; 9 typedef long long LL; 10 LL dp[MAXN], w[MAXN][MAXN]; 11 int len[MAXN]; 12 int n, m; 13 LL solve() 14 { 15 memset(dp, 0, sizeof(dp)); 16 memset(w, -1, sizeof(w)); 17 for( int i = 0 ; i <= n ; i++ ) 18 { 19 for( int j = 0 ; j <= n ; j++ ) 20 { 21 w[0][j] = 0; 22 } 23 } 24 for( int i = 1 ; i <= n ; i++ ) 25 { 26 for( int j = i ; j <= n ; j++ ) 27 { 28 int tmp = m - (j-i) - (len[j]-len[i-1]); 29 if( tmp < 0 ) 30 { 31 break; 32 } 33 w[i][j] = tmp*tmp*tmp; 34 } 35 } 36 dp[0] = 0; 37 for( int i = 1 ; i <= n ; i++ ) 38 { 39 dp[i] = dp[i-1]+w[i][i]; 40 for( int j = i-1 ; j >= 0 ; j-- ) 41 { 42 if( w[j+1][i] < 0 ) break; 43 dp[i] = min(dp[i], dp[j] + w[j+1][i]); 44 } 45 } 46 LL res = dp[n]; 47 for( int i = n ; i >= 0 && w[i][n] >= 0 ; i-- ) 48 { 49 res = min(res, dp[i-1]); 50 } 51 return res; 52 } 53 int main(int argc, char *argv[]) 54 { 55 while( scanf("%d%d", &n, &m)!=EOF ) 56 { 57 len[0] = 0; 58 for( int i = 1 ; i <= n ; i++ ) 59 { 60 scanf("%d", &len[i]); 61 } 62 for( int i = 2 ; i <= n ; i++ ) 63 { 64 len[i] = len[i-1] + len[i]; 65 } 66 printf("%lld\n", solve()); 67 } 68 } 69 //input:(n, m, arr[i]) 70 //5 5 71 //4 1 1 3 3 72 //5 6 73 //1 3 3 2 3 74 //output: 75 //17 76 //1