算法设计与分析:第五章 回溯法 5.9连续邮资问题

/*
连续邮资问题:
假设国家发行了n种不同面值的邮票,并且规定每张信封上最多只允许贴m张邮票。连续邮资问题要求对于给定的n和m的值,给出邮票面值的最佳设计,在
一张信封上可以贴出从邮资1开始,增量为1的最大连续邮资区间。

举例分析:
当n=2,m=3时,如果面值分别为1和4,则可以获得的邮资范围为1~6 加上 8 , 9 , 12
如果过面试为1,3,则可以获得1~7之间的每个邮资值,并且7就是可以得到的连续的邮资最大值


问题分析:
寻找子集就是子集树
寻找元素排列就是排列树
这是子集树问题,因为要求一个集合S,集合S中的元素满足某种性质。是从n个元素的集合S中,找出S满足某种性质的子集
思路:搜索可行解
解向量:用n元组x[1:n]表示n总不同邮票面值,从小到大排列
约束函数:若选定x[1:i-1],并且取值范围为:1~r,那么x[i]取值范围为x[i-1]+1~r+1

如何确定r的值?
计算x[1:1]的最大连续邮资区间时,直接递归复杂度较高。
尝试计算用不超过m张面值为x[1:i]贴出邮资k所需的最少邮票数为y[k],通过y[k]可以推算出r(最大连续邮资)的值,
y[k]可以通过递推在O(n)时间内解决


不懂
算法步骤:
1 初始化数组
2 计算任意邮资需要的最少张数
3 判断是否越界,并更新最优值
4 拷贝数组,对x[i]范围的x[i-1]+1 到 r,更新当前解,递归调用 , 回溯

输入:
2(邮票的种类数) 3(允许张贴的邮票数)


2 3


5 4

输出:
7
1 3

70
1 3 11 15 32
*/

#include 
#include 

using namespace std;

int n ,m ;     //邮票种类数,邮票允许的张帖数
int x[100];    //当前解
int bestx[100];//当前最优解
int y[10000];  //贴出各种邮资所需要的最少邮票数
int maxint;    //大整数
int maxl;      //邮资上界 
int maxvalue;  //当前最优值


void backTrace(int i ,int r)
{
	//递推求解任意邮资所需要的最少邮资数
	int z[10000];
	for(int j = 0 ; j <= x[i-2]*(m-1) ; j++)//这里是x-2
	{
		//如果小于最多邮资数
		if(y[j] < m)
		{
			for(int k = 1 ; k <= m - y[j] ; k++)
			{
				//更新邮资所需的最少张数
				if(y[j] + k < y[j + x[i-1] * k] )
				{
					y[j + x[i-1]* k ] = y[j] + k;
				}
			}
		}
	}
	//更新最大连续邮资值
	while(y[r] < maxint )
	{
		r++;
	}
	//判断是否搜索到最优解
	if(i > n)
	{
		//判断是否超过最优解
		if(r - 1 > maxvalue)//?r - 1
		{
			maxvalue = r - 1;
			//更新最优解
			for(int p = 1 ; p <= n ; p++)
			{
				bestx[p] = x[p];
			}
			return ;//易错,直接退出
		}
	}
	//拷贝邮资最少张数数组,用于回溯,对于每个x[i]的可能值进行赋值并求解
	for(int k = 1 ; k <= maxl; k++)
	{
		z[k] = y[k];
	}
	for(int j = x[i-1] + 1 ; j <= r ; j++)
	{
		x[i] = j ;
		backTrace( i+1 , r);//递归下一个编号
		//回溯
		for(int k = 1 ; k <= maxl; k++)
		{
			y[k] = z[k];
		}
	}
}


void process()
{	
	while(cin >> n >> m)
	{
		maxint = 32767;
		maxl = 1500;
		maxvalue = 0;
		//初始化解
		memset(x , 0 , sizeof(x));
		//初始化邮资所需要的最少张数
		for(int i = 1 ; i <= maxl ; i++)
		{
			y[i] = maxint;
		}
		y[0] = 0;
		x[1] = 1;//第一个邮票面值必须为1
		backTrace(2,1);//第一个参数是邮票编号,第二个参数是最大连续邮资
		cout << maxvalue;

	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

你可能感兴趣的:(算法设计与分析,算法设计与分析,回溯)