題意:
給n個單詞的長度和每行最多能放的字符數m,每行產生的值為(m-x)^2,x是該行的字符數(包括單詞之間的空格),求把所有單詞放完產生的值的最小和。
分析:
動態規劃很重要的就是狀態的定義,在由子問題向父問題推進的過程中,定義的狀態要能對之前的所有情況進行總結,比如背包問題中dp[i][v]中的v,不管之前1~i-1個物品如何取捨,他們的總重量肯定在0~v之中,故每步能把指數級的問題線性化。這題也是,剛考慮第i個單詞時,前面所有單詞不管怎麼放最後一個的結束位置肯定在1~m之間,故定義dp[i][s](s<=m)表示放完前i個單詞第i個單詞末位位於該行s處的最小值。
代碼:
//poj 3390 //sep9 #includeusing namespace std; const int maxM=108; const int maxN=10004; int dp[maxN+10][maxM+10]; int L[maxN]; int main() { int cases; scanf("%d",&cases); while(cases--){ int m,n,s; scanf("%d%d",&m,&n); for(int i=1;i<=n;++i) scanf("%d",&L[i]); memset(dp,0x7f,sizeof(dp)); dp[0][m]=0; for(int i=1;i<=n;++i){ int x=dp[maxN][maxM]; for(s=m;s>=0;--s) x=min(x,dp[i-1][s]); dp[i][L[i]]=x+(m-L[i])*(m-L[i]); for(s=L[i]+2;s<=m;++s){ int x=s-L[i]-1; if(dp[i-1][x]==dp[maxN][maxM]) continue; int y=dp[i-1][x]-(m-x)*(m-x)+(m-s)*(m-s); dp[i][s]=y; } } int ans=dp[0][maxM]; for(s=0;s<=m;++s) ans=min(ans,dp[n][s]); printf("%d\n",ans); } return 0; }