#include "stdio.h"
#include "string.h"
#define INF 2147483647
#define MAX 10 //最多邮票种数
#define MAXV 1024 //邮资上界
int x[MAX]; //存储邮票面值
int bestx[MAX];
int maxValue = 0; //最优值,最大的连续邮资区间
int r; 当前最优值,当前最大的连续邮资区间
int n; //邮票总数
int m; //一个信封上最多能贴的邮票数
int y[MAXV]; //y[i]表示用不超过m张邮票贴出邮资为i所需的最少邮票数
//当前在i层,能贴出的连续邮资区间为r
void backtrack(int i)
{
if(i>=n) //如果到达叶结点
{
if(r>maxValue) //邮票能表示的最大连续区间更大
{
memcpy(bestx, x, sizeof(x)); //拷贝最优解
maxValue = r; //更新最优值
}
return;
}
else
{
int z[MAXV];
memcpy(z, y, MAXV);
int tempr = r;
int j;
//下一个邮资面额的选择,肯定比之前的邮票面值大,但最大为之前能贴出的邮资区间+1,否则可能出现区间不连续
for(j=x[i-1]+1; j<=r+1; j++)
{
x[i] = j; //选择了面值j
//动态规划,更新y值
int v;
for(v=0; v<x[i-1]*m; v++) //当前邮票所能组成面值的最大值
{
if(y[v]<m) //当x[i]的面额确定后,如果邮票不满m张
{
int k;
for(k=1; k<=m-y[v]; k++) //那就一直贴x[i],直到达到m张
if((y[v]+k<y[v+x[i]*k]) && v+x[i]*k<MAXV) //在这个过程中产生了新的邮资:v+x[i]*k
y[v+x[i]*k] = y[v]+k; //取能产生最多不同邮资的用邮票数最少的那个元素
}
}
//如果y[r+1]的值在上述动态规划运算过程中已赋值,则y[r+1]<INF
while(y[r+1]<INF) r++; //更新r值 ???????????????????????不懂
backtrack(i+1); //搜索下一层
memcpy(y, z, MAXV); //复原状态,为返回上一层作准备
r = tempr;
}
}
}
void maxStamp(int n1, int m1)
{
n = n1;
m = m1;
x[0] = 1; //第一张邮票的面值为1
int i;
for(i = 0; i <= m; i++) y[i] = i;
while(i < MAXV) y[i++] = INF;
r = m;
backtrack(1);
}
int main()
{
int n1 = 5;
int m1 = 4;
printf("邮票种数:%d\n", n1);
printf("每张信封上最多能贴%d张邮票\n", m1);
maxStamp(n1, m1);
printf("所设计的邮票面额为:\n");
int i;
for(i=0; i<n; i++)
printf("%d ", bestx[i]);
printf("\n");
printf("最大连续邮资区间为:1 ~ %d\n", maxValue);
return 0;
}
连续邮资问题
最新推荐文章于 2022-03-16 18:35:52 发布