這是演算法導論動態規劃一章的課後思考題
題目如下:
由給定的
n個英文單詞組成一篇文章,每個單詞的長度
(字元個數
)依次為
l1,l2...
要在一台印表機上將這段文章漂亮的列印出來.印表機每行最多可列印m個字元.這裡說說的漂亮定義如下:在印表機所列印的每一行中,行首和行尾可不留空格;行中每兩個單詞之間可留乙個空格;如果在一行中列印從單詞
i到單詞
j的字元,則按照列印規則,應該在一行中列印
sum(li,i<=i個字元,且不允許將單詞打破多餘的空格數為m
-j+i-sum(li,i<=i除文章的最後一行外,希望每行多餘的空格數目盡可能少,以每行多餘空格數的立方和達到最小作為漂亮的標準(最後一行不算).
比如m=5 a
︻bc︻d
︻ef︻g
(最後一行不算)
︻表示空格
總空餘為
1*1*1+1*1*1=2
最近一直在研究動規方面的問題,看到這道題後略一思索便想出了該問題的最優子結構:最後一行必定是從i到
n,當然
i必須在能夠列印的範圍內。
i定下來之後,前面的段落必定是最小和,否則必定能找到乙個更優解。這樣不斷迭代到初始情況,便可解決問題。
找到最優子問題結構只是動規的第一步。接下來還剩下一些問題:(1
)狀態變數如何表示??一維?二維??(2
)邊界情況如何處理。
一、最後一行不算,應該如何處理?
二、每一行是否超出最大字元數如何判斷?
三、初始狀態怎麼處理?
先來看狀態變數。剛一開始可能會想到用二維
dp。但仔細想過後發現無法實現。於是轉向一維,我們以陣列
c[j]
表示以第
j個元素結尾的段落,且第
j+1個另起一行。這樣便寫出了狀態轉移方程
c[j]=max (1<=i<=j),
其中lc(i,j)
表示以i
起頭,以
j結尾的一行。這樣便刻畫出了我們一開始想到的最優子結構!
接下來是邊界處理。我們假設資料下標從
1開始。那麼可取
c[0]=0
,如果取
c[0]
作為次狀態,那麼表示當前狀態處在第一行。比如,
c[1]=c[0]+lc(1,1)=l1
。然後我本來準備進行判斷,如果i到
j超過規定字元,則
i++。然後如果
j=n,並且i到
j在規定字元內,
c[j]=max;
(1<=i<=j)
。那麼狀態轉移就變成了(1
)max (1<=i<=j&&lc(i,j)<=m)//
正常情況
c[j]= (2
)c[i-1](j=n&&1<=i<=j&&lc(i,j)<=m)//
最後一行
這樣實現起來要加上許多判斷,就顯得很繁瑣。
導論上的方法是,令lc()
的返回值有三種狀態:正常,
0,無窮。這樣只需乙個狀態轉移
c[j]=max (1<=i<=j),
並且自動過濾掉了邊界情況,漂亮!
至此問題已全部解決,可以開始寫**了。從這個例子可以看出,dp
的邊界情況處理是非常重要的。我們的解題順序大致是:刻畫最優子結構
à刻畫狀態變數
à考慮邊界情況
à寫**。本人也是初學
dp不久,只是寫一寫自己的思考,歡迎高手指正j
源**:
#include
using namespace std;
int m,n;//
每行最大容量
int c[1000];//
狀態陣列
int l[1000];
int p[1000];//
儲存記錄用於重構最優解的陣列
//lc
函式用來分類,把邊界情況考慮進去,好想法!!!
int lc(int i,int j)
void prettypainting() }
cout< }
int main()
漂亮列印問題與動規模型的建立
這是演算法導論動態規劃一章的課後思考題 題目如下 由給定的n個英文單詞組成一篇文章,每個單詞的長度 字元個數 依次為l1,l2.要在一台印表機上將這段文章漂亮的列印出來 印表機每行最多可列印 個字元 這裡說說的漂亮定義如下 在印表機所列印的每一行中,行首和行尾可不留空格 行中每兩個單詞之間可留乙個空...
動規之遊艇租用問題
問題描述 長江俱樂部在長江設定了n個遊艇出租站1,2,n,遊客可在這些遊艇出租站租用遊艇,並在下游的任何乙個遊艇出租站歸還遊艇。遊艇出租站i到遊艇出租站j之間的租金為r i,j 設計乙個演算法,計算出從出租站1到出租站n所需要的最少租金。樣例輸入 35 15 7樣例輸出 12分析 fin i j 表...
矩陣連乘問題 區間動規
解答想法 共兩行第一行n 1 n 100 代表矩陣個數。第二行有n 1個數,分別為q 0 q 1 q n 1 q k 2000 代表第 k 個矩陣是q k 1 xq k 維的。共兩行第一行 m,為最優代價。注 測試用例中 m 值保證小於 2 31 第二行為最優順序。如 a1 a2a3 a4 最外層也...