连续邮资问题并输出搜索树

本文介绍了一种利用暴力搜索和回溯策略解决连续邮资问题的算法,通过实例演示如何为给定的邮票种类和张数限制找出最佳邮资组合。算法详细展示了如何构造邮票面值数组、使用occur数组跟踪组合状态,并输出包含面值、范围和搜索树的输出结果。
摘要由CSDN通过智能技术生成

连续邮资问题并输出搜索树


假设国家发行了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();
}

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值