动态规划;漂亮打印问题;时间复杂度O(n方); 思考方法记录在内;

#include <iostream> using namespace std; //漂亮打印问题 //穷举法:根据递归树,当前层可以放前几个单词,下一层分别又可以放剩余的前几个单词, 所以穷举规模为指数级,不合理。 //具有最优子结构性质: //当满足 : 求和{ (lengthOfWords i -> j) +(j-i) } <= M 时, 即i 到j的单词可以放入一行,此时 m[i][j]=0 ,此行即打印的最后一行,空格数不记录,所以m[i][j]=0 //当不满足上述条件时: m[i][j]=min{( M-i到k的长度和-(j-i) )的二次方 + m[k+1][j] } ,此时必须满足 k的范围: i到k的单词长度和+k-i(空格数) <=M //如果想在计算出最少空格次方数的基础上进一步记录分行情况,可以设置一个numOfWords大小的二维数组best[][],记录least[i][numOfWords]计算出时的断点单词位置, //然后从least[1][numOfWords]开始,找出best[1][numOfWords]的位置k,从此处断开,继续查询best[k][numOfWords]查找断点单词 class PerfectOutput { private: int **leastSpace;//二维数组leastSpace[i][j]记录第i个单词到第j个单词最少打印空格数 char **string;//用于输入并记录单词 int *lengthOfWords;//记录每个单词的长度 int numOfWords;//单词的数量 int maxNum;//一行最大字符数量 public: //构造函数,保证:M大于最大的单词长度 PerfectOutput(int numOfWords,int M) { this->numOfWords=numOfWords; maxNum=M; //开辟动态规划表与字符串数组 leastSpace=new int* [numOfWords+1]; for(int i=0;i<=numOfWords;i++) { leastSpace[i]=new int[numOfWords+1]; } string=new char*[numOfWords+1]; for(int j=0;j<=numOfWords;j++) { string[j]=new char[20];//给每个单词留够20个字符长度 } //开辟数组记录每个单词的长度 lengthOfWords=new int[numOfWords+1]; } //输入单词长度与单词 void input() { int i=1; while(i<=numOfWords) { cout<<"输入第"<<i<<"个单词的长度"<<endl; cin>>lengthOfWords[i]; cout<<"输入第"<<i<<"个单词"<<endl; cin>>string[i]; i++; } } //动态规划核心算法 void perfectOutput() { //初始化从最后一个往前数起能容纳在一行内的情况,记录其表值为0,即最后一行的空格数不计 int temp=lengthOfWords[numOfWords]; int i=numOfWords; while(temp<=maxNum&&i>=1) { leastSpace[i][numOfWords]=0; i--; if(i>=1) { temp+=lengthOfWords[i]+1; } } if(i<1) { return; } //继续从i往前递推计算,i此时为第一个单词,其到最后一个单词的长度和无法容纳在一行内,所以需要计算 for(;i>=1;i--) { //因为一个单词一定可以放在当前行,所以根据递归定义,设其值为(maxNum-lengthOfWords[i])*(maxNum-lengthOfWords[i])+leastSpace[i+1][numOfWords] leastSpace[i][numOfWords]=(maxNum-lengthOfWords[i])*(maxNum-lengthOfWords[i])+leastSpace[i+1][numOfWords]; temp=lengthOfWords[i];//记录i到k的长度,不能超过行长度的限制 for(int j=i+1;j<=numOfWords&&temp<=maxNum;j++)//在长度不超过行长度的条件下,找出一个最优值赋值给leastSpace[i][numOfWords] { temp=sum(i,j)+j-i;//计算此行单词+空格长度 if(temp<=maxNum)//如果没超过行长度 { if((maxNum-temp)*(maxNum-temp)+leastSpace[j+1][numOfWords]<leastSpace[i][numOfWords])//循环判断这种情况下的i到numOfWords段中空格方的总大小,取最小值 { leastSpace[i][numOfWords]=(maxNum-temp)*(maxNum-temp)+leastSpace[j+1][numOfWords]; } } else { break; } } } } //求i->j单词的长度和 int sum(int i,int j) { int localSum=0; while(i<=j) { localSum+=lengthOfWords[i++]; } return localSum; } //输出leastSpace[1][numOfWords],其值为最少的空格立方和数 void display() { cout<<leastSpace[1][numOfWords]<<endl; } }; void main() { PerfectOutput test(3,6);//3个单词,每行最大容纳6个字符 test.input();//输入数据 test.perfectOutput();//漂亮打印 test.display();//输出结果 }

考虑动态规划题目,首先从题目的要求入手。
例如此题:要求找出最少空格数的方案,其初始范围是n个单词的最少空格数。 那么,我们手动执行这个过程的时候,首先用单词去往第一行放,这一行会有一个空格数,然后再去计算剩下的单词的最少空格数,当前空格数+剩下单词的最少空格数就是最终的解,然而子问题也是最少空格数的求解。  再进一步看,求最少空格数,我们需要安排前边的某几个单词放置于当前行,然后计算剩余的单词的最少空格数,所以我们需要求出到底在该行放置多少个单词,并且字符数量不超过行字符数量的限制的情况下,加上剩余单词的最少空格数量,取所有情况的一个最小值,那么这个问题就得到了一个最优值。  子问题和父问题具有相同的性质,即最优性,不同于穷举方法。 这里我们计算得到的值都是最优的,而且父问题的最优值不会影响子问题的最优值,子问题完全由子问题来确定,这就是没有后效性。 另外,由于每一层可以放不同数量的单词,我们需要分别计算,找一个最小的,再子问题中,大范围的子问题的子问题会包含小范围的子问题,就是有重叠的问题。

说到这里,就可以根据最优+无后效+重叠的性质,选择动态规划自底向上的算法递推得到最终结果。

你可能感兴趣的:(算法,String,Class,input,include)