解题思路:既然是用动态规划方法。那么想办法把第i个单词到第j个单词制作成一个表格,这个表格用于存放剩余空格数,代价以及代价和,当中代价剩余空格数的立方。

                  于是有例如以下定义:

                  定义extra[i][j]=M - j + i - ∑lk ,当中k = i, ..., j。表示剩余的空格数

                  定义lc[i][j]表示每行空格数的立方值,INF表示无穷大. 当数组extra[i][j]<0时,lc[i][j]=INF;当j==n且extra[i][j]≥0时,表示已经到最后一行,lc[i][j]=0;其它情况lc[i][j]=(lc[i][j])3

                  定义c[j]表示从1到i的空格数立方和。有递归式:c[j]=c[i-1] + lc[i][ j]。c[0]=0。当j>0,(1≤i≤j)c[j]=min(c[i - 1] + lc[i - 1][ j]  。

  

 代码例如以下:(注意本代码是将《教师手冊》伪代码转换成了C/C++程序,可是当中对伪代码做了改动,为了能使程序正确执行,某些地方是伪代码没有的。)

//15-4对于自己主动换行问题的动态规划解决方式
#include <limits.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define INF INT_MAX
//一种有用功能打印解决方式
int GIVE_LINES (int p[], int j,char *str[]);

// l[]表示不同单词的输入序列的长度。

比如。 // l[] = {3, 2, 2, 5} 对于像 "aaa bb cc ddddd"一句. n 是大小尺寸。 // l[] M 是一行宽度 (没有最大字符串能填满一行) void PRINT_NEATLY (int l[],char *str[],int n,int M) { //为简单起见,extra数组空间用于存放每行剩余空格数 //假设从单词i到单词j能够放在一行,那么extras[i][j]表示剩余空格数 //int extras[n+1][n+1]={0}; int **extras,i,j; extras=new int*[n+1]; for ( i=0;i<=n;i++) { extras[i]=new int[n+1]; } //lc[i][j]表示从单词i到单词j的一行的代价(空格数的立方) int **lc; lc=new int*[n+1]; for ( i=0;i<=n;i++) { lc[i]=new int[n+1]; } //c[i]表示从单词i到单词j最优代价和(空格数最小立方和) int *c=new int[n+1]; // p[] 用于打印解决方式 int *p=new int[n+1]; //计算每行的剩余空格数。 //若单词i到单词j能够放到一行,那么extra[i][j]值意味着是此行的剩余空格数。

for (i = 1; i <= n; i++) { extras[i][i] = M - l[i-1];// for (j = i+1; j <= n; j++) { extras[i][j] = extras[i][j-1] - l[j-1] - 1; } } //用上述剩余空格数(数组extra)来计算行代价(数组lc)。 //若单词i到单词j能够放到一行,lc[i][j]值表示此行的代价。 for (i = 1; i <= n; i++) { for (j = i; j <= n; j++) { if (extras[i][j] < 0) lc[i][j] =INF; else if (j == n && extras[i][j] >= 0) lc[i][j] = 0; else lc[i][j] = extras[i][j]*extras[i][j]*extras[i][j]; } } //计算最小代价而且找到最小代价的每行换行处。 //c[j]意味着从单词1到单词j的最优总代价(代价=立方和) c[0] = 0; for (j = 1; j <= n; j++) { c[j] = INF; for (i = 1; i <= j; i++) { if (c[i-1] != INF&&lc[i][j] != INF && (c[i-1] + lc[i][j] < c[j])) { c[j] = c[i-1] + lc[i][j]; p[j] = i; } } } GIVE_LINES(p, n,str); } int GIVE_LINES(int p[], int j,char *str[]) { int k,i=p[j]; if (i == 1) k = 1; else k = GIVE_LINES (p, i-1,str) + 1; cout<<"Line number:"<<k<<" "; for (int t=i;t<=j;t++) { cout<<str[t-1]<<" "; } cout<<endl; return k; } //主程序測试上述功能 int main() { const int n=10;//一共同拥有10个单词 const int M=8;//每行最多容纳8个字符 char*str[n]={"abc","def","gh","polq","cs","opaqe","klfgh","t","asd","th"}; int l[n]={0}; for (int i=0;i<n;i++) { l[i]=strlen(str[i]); } PRINT_NEATLY (l,str,n,M); return 0; }

例子输出

最后总结:程序执行时间是O(n²),《教师手冊》给的思路是正确的。可是答案不完整。

假设所有依照书上的伪代码转换成相应变成语言的话,你会发现程序不能正确执行进而怀疑程序的正确性。可是实际上程序大致没问题。就是有些推断和边界条件没有写清楚。这些须要对题目有所理解后,才干加入正确的代码。详细哪里有改动请看上面代码。