标签:style blog http os io strong for 2014
解题思路:既然是用动态规划方法,那么想办法把第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(n2),《教师手册》给的思路是正确的。但是答案不完整。如果全部按照书上的伪代码转换成对应变成语言的话,你会发现程序不能正确运行进而怀疑程序的正确性,但是实际上程序大致没问题,就是有些判断和边界条件没有写清楚,这些需要对题目有所理解后,才能添加正确的代码。具体哪里有修改请看上面代码。
标签:style blog http os io strong for 2014
原文地址:http://blog.csdn.net/z84616995z/article/details/38468273