题目:给你一段文字,让你对文字排版,每行的最大长度有限制L,有一个对于排版格式的权值公式:
P = sum((单词间空格-1)*(单词间空格-1))
求出P最小的一种排版,F相同时输出前面的空格最少的。
分析:DP。看见题目第一想到的就是利用dp,设F(i,j)是从第i个单词开始排版,到第j个单词结束的最小P
可以得到状态转移方程:
F(i,j)= min(F(i,k-1)+min_line(k,j)),i< k <= j 且 k到j的单词总长+j-k坏人空格不超过L
其中,min_line(k,j)是以k开始,j结束的一行的最小的P:
可以证明当每一行的单词确定后,平均分配中间的间隔,可以使得min_line最小。
最后,要注意计算的方向是从后向前,因为要保证前面的空格最少。
对于输出,保留上一行结束位置,每行单独计算即可。
(按顺序计算,后计算的优先级高,想一想求最短路时,如果保存路径使得前面路段最短,要逆向运算)
注意:数据的读入格式有点恶心。
// a+b = c, aa + bb = aa + (c-a)(c-a) = cc + 2aa - 2ac,最值在 2a = c
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
typedef struct dnode
{
char word[85];
int length;
}data;
data D[10005];
int sumL[10005];
int F[10005];
int E[10005];
void output( int i, int width, int max )
{
if ( i < max ) {
if ( E[i] > i+1 ) {
//计算每行中具体的空格分布
int sblack = width-sumL[E[i]-1]+sumL[i-1];
int eblack = sblack/(E[i]-1-i);
int nshort = (eblack+1)*(E[i]-1-i)-sblack;
int count = 0;
printf("%s",D[i].word);
for ( int j = i+1 ; j < E[i] ; ++ j ) {
for ( int k = 0 ; k < eblack ; ++ k )
printf(" ");
if ( ++ count > nshort ) printf(" ");
printf("%s",D[j].word);
}printf("\n");
}else printf("%s\n",D[i].word);//自己独立一行
output( E[i], width, max );
}
}
int main()
{
int width,temp;
while ( scanf("%d",&width) && width ) {
getchar();
int count = 1;
while ( (temp = getchar()) != '\n' ) {
do {
ungetc( temp, stdin );
scanf("%s",D[count].word);
D[count].length = strlen(D[count].word);
count ++;
}while ( (temp = getchar()) != '\n' );
}
sumL[0] = 0;
for ( int i = 1 ; i < count ; ++ i )
sumL[i] = sumL[i-1]+D[i].length;
F[count] = 0;
for ( int i = count-1 ; i > 0 ; -- i ) {
F[i] = F[i+1] + 500;
E[i] = i+1;
for ( int j = i+1 ; j < count && sumL[j]-sumL[i-1]+j-i <= width ; ++ j ) {
//计算每行中具体的空格分布
int sblack = width-sumL[j]+sumL[i-1];
int eblack = sblack/(j-i);
int nshort = (eblack+1)*(j-i)-sblack;
int add = (j-i-nshort)*eblack*eblack+nshort*(eblack-1)*(eblack-1);//本行代价
if ( F[i] >= F[j+1] + add ) {
F[i] = F[j+1] + add;
E[i] = j+1;
}
}
}
output( 1, width, count );
printf("\n");
}
return 0;
}
附上两组比较恶心的数据:
input:
25
x x x x x xxxxxxxxxxxxxx
x xxxxxxxxxxxx
xxxxxxxxxxx x
xxxxxxxxxxxxxx x x x x x
5
La la la
output:
x x x x x xxxxxxxxxxxxxx
x xxxxxxxxxxxx
xxxxxxxxxxx x
xxxxxxxxxxxxxx x x x x x
La la
la