文本排版规划

问题描述:

输入n个单词,各单词长度分别为box[i].w(即每个单词的字母数,i=1…n),单词为box[i].s。

struct BOX {
	char s[Wp];//单词最大长度为15
	int w;//单词长度
};

已知页面宽度为Wp(即该页每行容许的最大字母数)。要求输出每一行的单词分布。排版单词时,要求不改变各单词原来的顺序,且页面每一行各单词累加的长度不能超过页面宽度。 为了评价每行的排版美观程度,定义如下函数:

badness[i][j]=
当WL[i][j] > Wp,badness[i][j] = MAX
当WL[i][j] <= Wp,badness[i][j] = (Wp - WL[i][j])^3

其中,WL[i][j]表示第i个单词到第j个单词的累加宽度,Wp为页面宽度。该函数是每一行排版空白数的指标。函数取3次方,是为了增大差异值,凸显一行中存在空白的不美观程度。因此,可以认为badness越小越美观。

例如,页面宽度为20,有5个单词序列[good, good, good, good, good],各个单词有4个字母,其宽度均为4。则:当一行中只有前2个单词时,badness(1,2) = (20-(4+4))3=1728;当一行中只有前3个单词时badness(1,3) = (20-(4+4+4))3=512;当一行中只有前四个单词时badness(1,4) =(20-(4+4+4+4))3=64。按照badness越小越美观的标准,显然一行中排前四个单词的方案优于前二者。

问题:

求解任意输入的n个单词的最优排版方案,要求单词之间最少应存在一个空格。



void main()
{
	int n;
	cout << "共有多少个单词:";
	cin >> n;
	BOX* box = CreateBox(n);
	cout << "\n\n";
	int** L = CreateWL_(n, box);
	//int** L = CreateWL(n, box);
	

	//1,2和3,4最优解不一定相同
	//1,2两种方式最优解一定相同,但S不一定相同
	if (1)
	{
		int** key = CreateKey(n);
		short** s = CreateS(n);

		long** badness = CreateBadness(n, L);
		//long** badness = CreateBadness_(n, L);
		
		RecurBest_u_d(badness, 1, n, s, key);
		PrintfBest(box, 1, n, s);
	}

	if (2)
	{
		int** key = CreateKey(n);
		short** s = CreateS(n);

		long** badness = CreateBadness(n, L);
		//long** badness = CreateBadness_(n, L);
		
		CirculateBest_u_d(badness, 1, n, s);
		PrintfBest(box, 1, n, s);
		PrintfBadness(1, n, badness);
	}

	//3,4两种方式最优解一定相同,但S不一定相同
	if (3)
	{
		int** key = CreateKey(n);
		short** s = CreateS(n);

		long** badness = CreateBadness(n, L);
		//long** badness = CreateBadness_(n, L);
		
		RecurBest_d_u(badness, 1, n, s, key);
		PrintfBest(box, 1, n, s);
	}

	if (4)
	{
		int** key = CreateKey(n);
		short** s = CreateS(n);

		long** badness = CreateBadness(n, L);
		//long** badness = CreateBadness_(n, L);
		
		CirculateBest_d_u(badness, 1, n, s);
		PrintfBest(box, 1, n, s);
		
	}

	system("pause");
	/*PrintfL(1, n, L);
	  PrintfS(1, n, s);*/
	  
}

测试例子:

//good book good book good book good book
//Do you like those people who always think of money and cannot remember the past

测试一截图:

alt

测试二截图:

alt

alt

#include<iostream>
using namespace std;
#define Wp 16//该页每行容许的最大字母数
#define Max 10000000//无穷大 

struct BOX {
	char s[Wp];//单词最大长度为15
	int w;//单词长度
};


BOX* CreateBox(int n);//记录单词信息矩阵
int** CreateKey(int n);//标记函数,所有元素初始化为0,当badness[i][j]已是最优值时将key[i][j]置为1
short** CreateS(int n);//划分矩阵

int** CreateWL(int n, BOX* box);//记录长度矩阵,未加空格,和CreateBadness_()配合使用
long** CreateBadness_(int n, int** L);//初始化美观程度评价矩阵,内部计算所需空格数并减去,和CreateWL()配合使用
int** CreateWL_(int n, BOX* box);//记录长度矩阵,在原来单词长度基础上加上一个空格的长度,和CreateBadness()配合使用
long** CreateBadness(int n, int** L);//初始化美观程度评价矩阵,和CreateWL_()配合使用

long RecurBest_d_u(long** badness, int i, int j, short** s, int** key);//自底向顶递归求最优值
void CirculateBest_d_u(long** badness, int set, int end, short** s);//自底向顶循环求最优值
long RecurBest_u_d(long** badness, int i, int j, short** s, int** key);//自顶向底递归求最优值
void CirculateBest_u_d(long** badness, int set, int end, short** s);//自顶向底循环求最优值

void PrintfS(int set, int end, short** s);//打印划分矩阵
void PrintfL(int set, int end, int** L);//打印单词长度
void PrintfBadness(int set, int end, long** badness);//打印美观程度评价矩阵
void PrintfBest(BOX* box, int set, int end, short** s);//打印最优排版
#include "All.h"

BOX* CreateBox(int n)//记录单词信息矩阵
{
	int m = n + 1;
	BOX* box = new BOX[m];
	cout << "!!每个单词最大长度为15\n";
	cout << "请按顺序输入每一个单词,单词之间用空格隔开!\n";
	for (int i = 1; i < m; i++)
	{
		//cout << "第" << i << "个单词为:";
		cin >> box[i].s;
		box[i].w = strlen(box[i].s);
	}
	return box;
}




int** CreateKey(int n)//标记函数,所有元素初始化为0,当badness[i][j]已是最优值时将key[i][j]置为1
//当下一次需要获取badness[i][j]的最优值时,判断key[i][j]是否为1,是直接返回当前badness[i][j];否计算最优值badness[i][j]
{
	int m = n + 1;
	int** key = new int* [m];
	for (int i = 1; i < m; i++)
	{
		key[i] = new int[m];
		for (int j = 1; j < m; j++)
			key[i][j] = 0;
	}
	return key;
}




short** CreateS(int n)//划分矩阵
{
	short m = n + 1;
	short** s = new short* [m];
	for (short i = 1; i < m; i++)
	{
		s[i] = new short[m];
		for (short j = i; j < m; j++)
		{
			s[i][j] = -1;//在第i个单词后进行换行
		}
	}
	return s;
}




int** CreateWL(int n, BOX* box)//记录长度矩阵,未加空格,CreateBadness_()配合使用
{
	int m = n + 1;
	int** L = new int* [m];
	for (int i = 1; i < m; i++)
	{
		L[i] = new int[m];
		L[i][i] = box[i].w;
	}

	for (int i = 1; i < m; i++)
	{
		for (int j = i + 1; j < m; j++)
		{
			L[i][j] = 0;
			for (int k = i; k <= j; k++)
				L[i][j] = L[i][j] + L[k][k];
		}
	}
	return L;
}




long** CreateBadness_(int n, int** L)//初始化美观程度评价矩阵,内部计算所需空格数并减去,和CreateWL()配合使用
{
	int m = n + 1;
	int num;
	long** badness = new long* [m];
	for (int i = 1; i < m; i++)
	{
		badness[i] = new long[m];
		for (int j = i; j < m; j++)
		{
			num = j - i;//需要添加的空格数
			int overplus = Wp - L[i][j] - num;//空白数
			if (overplus >= 0)
				badness[i][j] = (overplus) * (overplus) * (overplus);
			else
				badness[i][j] = Max;
		}

	}
	return badness;
}




int** CreateWL_(int n, BOX* box)//记录长度矩阵,在原来单词长度基础上加上一个空格的长度,和CreateBadness()配合使用
{
	int m = n + 1;
	int** _L = new int* [m];
	for (int i = 1; i < m; i++)
	{
		_L[i] = new int[m];
		_L[i][i] = box[i].w;
	}

	for (int i = 1; i < m; i++)
	{
		for (int j = i + 1; j < m; j++)
		{
			_L[i][j] = 0;
			for (int k = i; k <= j; k++)
			{
				if (k < j)
				{
					_L[i][j] = _L[i][j] + _L[k][k] + 1;//多一个空格
				}
				else
					_L[i][j] = _L[i][j] + _L[k][k];//最后一个单词不用加空格
			}

		}
	}
	return _L;
}




long** CreateBadness(int n, int** L)//初始化美观程度评价矩阵,和CreateWL_()配合使用
{
	int m = n + 1;
	long** badness = new long* [m];
	for (int i = 1; i < m; i++)
	{
		badness[i] = new long[m];
		for (int j = i; j < m; j++)
		{
			int overplus = Wp - L[i][j];//空白数
			if (overplus >= 0)
				badness[i][j] = (overplus) * (overplus) * (overplus);
			else
				badness[i][j] = Max;
		}

	}
	return badness;
}




long RecurBest_d_u(long** badness, int i, int j, short** s, int** key)//自底向顶递归求最优值
{
	if (i == j)
	{
		return badness[i][j];//只有一个单词,已是最优值
	}
	else
	{
		if (key[i][j] == 1)
			return badness[i][j];//已有最优值,不需再递归计算
		else
		{
			for (int k = i; k <= j - 1; k++)//从底向顶(1,2,……,n-1,n)
			{
				long m = RecurBest_d_u(badness, i, k, s, key) + RecurBest_d_u(badness, k + 1, j, s, key);
				if (m < badness[i][j])
				{
					badness[i][j] = m;
					s[i][j] = k;
				}
			}
			key[i][j] = 1;
		}
	}
	return badness[i][j];
}




void CirculateBest_d_u(long** badness, int set, int end, short** s)//自底向顶循环求最优值
{
	for (int i = set; i < end; i++)
	{
		for (int j = i + 1; j <= end; j++)
		{
			for (int k = i; k <= j - 1; k++)//从底向顶(1,2,……,n-1,n)
			{
				long m = badness[i][k] + badness[k + 1][j];
				if (m < badness[i][j])
				{
					badness[i][j] = m;
					s[i][j] = k;
				}
			}
		}
	}
}




long RecurBest_u_d(long** badness, int i, int j, short** s, int** key)//自顶向底递归求最优值
{
	if (i == j)
	{
		return badness[i][j];//只有一个单词,已是最优值
		//s[i][i] = -1; 
	}
	else
	{
		if (key[i][j] == 1)
			return badness[i][j];//已有最优值,不需再递归计算
		else
		{
			for (int k = j - 1; k >= i; k--)//从顶向底(n,n-1,……,2,1)
			{
				long m = RecurBest_u_d(badness, i, k, s, key) + RecurBest_u_d(badness, k + 1, j, s, key);
				if (m < badness[i][j])
				{
					badness[i][j] = m;
					s[i][j] = k;
				}
			}
			key[i][j] = 1;
		}
	}
	return badness[i][j];
}




void CirculateBest_u_d(long** badness, int set, int end, short** s)//自顶向底循环求最优值
{
	for (int i = set; i < end; i++)
	{
		for (int j = i + 1; j <= end; j++)
		{
			for (int k = j - 1; k >= i; k--)//从顶向底(n,n-1,……,2,1)
			{
				long m = badness[i][k] + badness[k + 1][j];
				if (m < badness[i][j])
				{
					badness[i][j] = m;
					s[i][j] = k;
				}
			}
		}
	}
}




void PrintfS(int set, int end, short** s)
{
	cout << "\n***************s[i][j]***************\n";
	for (int i = set; i <= end; i++)
	{
		for (int j = i + 1; j <= end; j++)
		{
			cout << "s[" << i << "][" << j << "]=" << s[i][j] << "\t";
		}
		cout << "\n\n";
	}
}




void PrintfL(int set, int end, int** L)
{
	cout << "\n***************L[i][j]***************\n";
	for (int i = set; i <= end; i++)
	{
		for (int j = i + 1; j <= end; j++)
		{
			cout << "L[" << i << "][" << j << "]=" << L[i][j] << "\t";
		}
		cout << "\n\n";
	}
}




void PrintfBadness(int set, int end, long** badness)
{
	cout << "\n***************badness[i][j]***************\n";
	for (int i = set; i <= end; i++)
	{
		for (int j = i + 1; j <= end; j++)
		{
			cout << "badness[" << i << "][" << j << "]=" << badness[i][j] << "\t";
		}
		cout << "\n\n";
	}
}




void PrintfBest(BOX* box, int set, int end, short** s)
{
	int m = end - set + 1;
	int i = set;
	int j = end;
	int t = 0;//共m个单词,每输出一个,t++
	while (t <= m && s[i][j] != -1)
	{
		int k = j;
		while (s[i][k] != -1)
		{
			k = s[i][k];
		}
		for (int w = i; w <= k; w++)
		{
			cout << box[w].s << "*";
			t++;
		}
		cout << "\n";
		i = k + 1;
	}
	if (t <= m)
	{
		for (int w = i; w <= j; w++)
		{
			cout << box[w].s << "*";
			t++;
		}
		cout << "\n";
	}
	cout << "\n\n";
}
全部评论

相关推荐

jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
头像
11-09 12:17
清华大学 C++
out11Man:小丑罢了,不用理会
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务