自动换行问题(word wrap problem )几种解法之比较

问题描述:

给定一个单词序列和一个每行最做可放多少个字符的限制。需要把这个单词序列按限制行宽摆放完,使得每行剩余的空间的成本和最小。

        在同一行不同单词见的空格符不计入剩余的空间。假定某行的剩余空间是N,则其成本是N*N,举例说明之:

假定给定序列为:"Geeks for Geeks presents word wrap problem", 每行宽度限制为15,

则最优的摆放为:

		   Geeks for Geeks
		   presents word
		   wrap problem 
    剩余空间的成本之和为: 0 + 2 * 2 + 3 * 3;
    具体问题的描述可见(www.geeksforgeeks.org)
 

问题解法:

    下面用三种解法给出答案,分别为
    1. 暴力搜索;
    2. 递归解法;
    3. 动态规划;(注:本文的动态规划解法直接来自geeksforgeeks,笔者目前还没找到更简单的动态规划实现)
       1,2仅能给出次优解法,他们的策略为贪婪策略;
 

解决代码:

 
#ifndef _WORD_WRAP_H_
#define _WORD_WRAP_H_

#include <stdlib.h>
#include <stdio.h>

/*
* The implementation of the method of brute force search for word wrap problem
*
*/
int WordWrapBrute( const int words[], int size, int width )
{
	int len = width;
	int cost  = 0;
	for( int i = 0; i < size; i++ ) // loop each word
	{
		if( len  >  words[i] )
		{
			len -= words[i] + 1;
		}
		else if( len == words[i] )
		{
			len -= words[i];
		}
		else if( len < words[i] )
		{
			if( len > 0 )
				cost += ( len + 1 ) * ( len + 1 );

			len = width;
			len -= words[i] + 1;
		}
	}

	return cost;
}

/*
* The implementation of recursive method for word wrap problem
*
*/
int WordWrapRecur( const int words[], int size, int cur, int rowIdx, int curWidth, int width )
{
	if( cur == size )
	{
		return 0;
	}

	for( int i = cur; i < size; i++ )
	{
		if( curWidth - words[i] >= 0 )
		{

			return  WordWrapRecur( words, size, i + 1, rowIdx, 
								   curWidth - words[i] - 1, width );
		}
		else
		{
			rowIdx++;
			if( curWidth != 0 )
			{
				return ( curWidth + 1) * ( curWidth + 1) +
                                        WordWrapRecur( words, size, i + 1, rowIdx, 
				                       width - words[i] - 1, width );
			}
			else
			{
				return WordWrapRecur( words, size, i + 1, rowIdx,
				                      width - words[i] - 1, width  );
			}
		}
	}
}

/*
* Output solution when apply to dynamic programming method
*
*/

int OutputSolution( int record[], int size )
{
	int k = -1;
	if( 1 == record[size] )
	{
		k = 1;
	}
	else
	{
		k = OutputSolution( record, record[size] - 1 ) + 1;
	}

	printf ("Line number %d: From word no. %d to %d \n", k, record[size], size);
	return k;
}

/*
* The implementation of dynamic programming for word wrap problem
*
*/
int WordWrapDP( const int words[], int size, int width )
{
	
	// construct table can be used to record the remainder space when from i to j  in single row
	int** table = new int*[size + 1];
	assert( table );
	for( int i = 0; i <= size; i++ )
	{
		table[i] = new int[ width + 1 ];
		assert( table[i] );
	}

	// calculate i to j remainder space in single row
	for( int i = 1; i <= size; i++ )
	{
		table[i][i] = width - words[i - 1];
		for( int j = i + 1; j <= size; j++ )
		{
			table[i][j] = table[i][j - 1] - words[j-1] - 1;
		}
	}

	// construct cost array
	int** cost = new int*[size + 1];
	assert( cost );
	for( int i = 0; i <= size; i++ )
	{
		cost[i] = new int[ width + 1 ];
		memset( cost[i], 0x00, sizeof(int)*( width + 1) );
		assert( cost[i] );
	}

	for( int i = 1; i <= size; i++ )
	{
		for( int j = i; j <= size; j++ )
		{
			if(  table[i][j] < 0 )
			{
				cost[i][j] = INT_MAX;
			}
			else if( size == j && table[i][j] >= 0 )
			{
				cost[i][j] = 0;
			}
			else
			{
				cost[i][j] = table[i][j] * table[i][j];
			}
				
		}
	}

	int* result = new int[size + 1];
	int* record = new int[size + 1];
	memset( record, 0x00, sizeof(int)*(size + 1) );

	result[0] = 0;
	for( int j = 1; j <= size; j++ )
	{
		result[j] = INT_MAX;
		for( int i = 1; i <= j; i++ )
		{
			if( result[i - 1] != INT_MAX && cost[i][j] != INT_MAX && 
				result[i - 1] + table[i][j] < result[j] )
			{
				result[j] = result[i - 1] + table[i][j];
				record[j] = i;
			}
		}
	}


    OutputSolution( record, size );

	for( int i = 0; i <= size; i++ )
	{
		delete [] table[i];
		delete [] cost[i];
	}

	delete [] table;
	delete [] cost;



	return 0;
}


void TestWordWrap()
{
	int words[] = {3, 2, 2, 5};
	int size = sizeof(words)/sizeof(words[0]);
	int width =  6;

	int cost = WordWrapRecur( words, size, 0, 1, 6, 6 );
	int newCost = WordWrapBrute( words, size, width );

	WordWrapDP( words, size, width );
	getchar();

}


#endif 


 
 
      


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值