题目链接:http://poj.org/problem?id=1093
题目大意:将一段文字重新排版,每行有n个字符,问最优方案,从后往前dp,令dp[i]为以第i个单词开始到结束的最小badness,并用p[i]记录以i开始的这一行的结束的单词,然后从前往后输出,则能保证空格排列的字典序最小。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<queue>
#include<algorithm>
#include<vector>
#include<stack>
#include<list>
#include<iostream>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
#define Max 110
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
int dp[10010],p[10010];
char str[11000];
char w[11000][82];
int n,len[11000],num,cnt,Len;
int count(int sumlen,int j)
{
// printf("ddd");
if(j==1)
return 500;
int a;
int q=(n-sumlen)/(j-1);
int r=(n-sumlen)%(j-1);
return a=r*q*q+(j-r-1)*(q-1)*(q-1);
// printf("%d",a)
}
int main()
{
int i,j,k,rec;
while(scanf("%d",&n),n)
{
getchar();
len[0]=0;
num=1;
cnt=0;
while(gets(str))
{
if(str[0]==0)
break;
Len=strlen(str);
for(i=0;i<Len;i++)
{
if(str[i]!=' ')
{
w[num][cnt++]=str[i];
}
else if(i&&str[i-1]!=' ')
{
len[num]=len[num-1]+cnt;
// printf("num %d len %d\n",num,len[num]);
w[num][cnt]=0;
num++;
cnt=0;
}
}
len[num]=len[num-1]+cnt; //printf("num %d len %d\n",num,len[num]);
w[num][cnt]=0;
num++;
cnt=0;
}
memset(dp,0,sizeof(dp));
for(i=num-1;i>=1;i--)
{
// printf("i %d %s\n",i,w[i]);
int MINX=inf;
for(j=1;i+j-1<num&&len[j+i-1]-len[i-1]+j-1<=n;j++)
{//printf("aa");
rec=dp[i+j]+count(len[i+j-1]-len[i-1],j);
if(rec<=MINX)//必须小于等于,这样才能保证最小字典序。
{
MINX=rec;
// printf("MIn%d\n",MINX);
p[i]=i+j-1;
}
}
dp[i]=MINX;
// printf("dp %d\n",dp[i]);
}
// printf("p %d\n",p[1]);
for(i=1;i<=num-1;i=p[i]+1)
{
if(p[i]-i+1==1)
{
printf("%s\n",w[i]);
continue;
}
int q=(n-(len[p[i]]-len[i-1]))/(p[i]-i);
int r=(n-(len[p[i]]-len[i-1]))%(p[i]-i);
// printf("q %d r %d\n",q,r);
for(j=i;j<p[i];j++)
{
printf("%s",w[j]);
for(k=1;k<=(j-i+1>p[i]-i-r)+q;k++)
printf(" ");
}
printf("%s\n",w[p[i]]);
}
puts("");
}
}