连续邮资问题并输出搜索树
假设国家发行了n种不同面值的邮票,并且规定每张信封上最多只允许贴m张邮票。连续邮资问题要求对于给定的n和m的值,给出邮票面值的最佳设计,在1张信封上可贴出从邮资1开始,增量为1的最大连续邮资区间。例如,当n=4和m=3时,面值为(1,4,7,8)的5种邮票可以贴出邮资的最大连续邮资区间是1到24。
算法设计:对于给定的n,m,计算最优分解方案。
数据输入:手动输入数据正整数n和m。
第一组测试数据:n=4,m=3;
第二组测试数据:n=5,m=4;
结果输出:将计算出的面值及范围以及搜索树 输出 到output.txt中,如下列文件所示。
连续邮资输出结果.txt
这里采用了暴力+回溯算法
#include<cstring>
#include<cstdio>
#include<iostream>
#include<fstream>
const int MAXN = 200;
using namespace std;
int m, n;
int ansStampVal[MAXN], ans, stampVal[MAXN], r[MAXN];
//最终邮票值,最终最大连续区间,过程邮票值,过程最大连续区间
bool occur[MAXN];//值是否能被组成
void dfs(int mcur, int n, int sum) {
occur[sum] = true;
if (mcur >= m) return;//达到邮票的最大张数
for (int i = 1; i <= n; ++i) {
dfs(mcur + 1, n, sum + stampVal[i]);
//对每种邮票不同张数都进行了遍历,得到现有邮票的所有组合值
}
}
void search(int i) {//对第i种邮票下进行搜索
ofstream pout;int j;
if (i > n) {
if (r[i - 1] > ans) {//如果第n张邮票的最大连续面额为当前最大
ans = r[i - 1];//更新最大连续面额
memcpy(ansStampVal, stampVal, sizeof(stampVal));//将邮票面额组合赋值给ans
}
return;
}
for (int next = stampVal[i - 1] + 1; next <= r[i - 1] + 1; ++next) {//第i种面额的可取值范围
stampVal[i] = next;//第i个邮票面值为 next
memset(occur, 0, sizeof(occur));//初始化出现数组
dfs(0, i, 0);//进行张数的搜索
int num = 0, j = 1,space=i;//space空格
while (occur[j++]) ++num;
r[i] = num;
pout.open("output.txt",ios::out| ios::app ,_SH_DENYNO);//输出
if (next> stampVal[i - 1] + 1&&next<= r[i - 1] + 1)
while (space > 0) { pout << "\t ";space--; }
pout << "(x" << i << "=" << next << ",r" << i << "=" << r[i] << ")(";
j = i;while (num > 0)//找到每个r的组成值
{
if (num - stampVal[j] == 0) { pout << stampVal[j] << ")"; break; }
else if (num - stampVal[j] > 0)
{
num -= stampVal[j];
pout << stampVal[j] << ",";
}
else j--;
}
pout.close();
search(i + 1);//对第i+1种邮票进行搜索
pout.open("output.txt", ios::out | ios::app, _SH_DENYNO);//换行
pout << endl;
pout.close();
}
}
int main() {
ofstream pout;
pout.open("output.txt",ios::trunc|ios::out);//清除存在文件
//n总数,m可用数
scanf("%d %d", &n, &m);
stampVal[1] = 1;
r[1] = m;
ans = -1;
pout << "(x1=1,r1=3)(1,1,1)";
pout.close();
search(2);//主要函数
pout.open("output.txt", ios::out | ios::app, _SH_DENYNO);//打开文件供写入,写于文末,允许其他程序可打开
pout << "n=" << n << ",m=" << m<<endl<<"X=<";
for (int i = 1; i <= n; ++i)//输出最终结果
if(i!=n)
pout << ansStampVal[i] << ",";
else
pout << ansStampVal[i] << "> ";
pout<<"[1,"<<ans<<"]";
pout.close();
}