class Stamp
{
friend int MaxStamp(int, int, int[]);
private:
void BackTrack(int i, int r);
int n, //邮票面值数
m, //每张信封最多允许贴的邮票数
maxvalue, //当前最优值
maxint, //大整数
maxl, //邮资上界
*x, //当前解
*y, //贴出各种邮资所需最少邮票数
*bestx; //当前最优解
};
void Stamp::BackTrack(int i, int r)
{//当前的邮票是x[i],r是x[1- i-1]邮票所能表示的最大的连续上界
int j;
int k;
for(int j=0; j<=x[i]*(m-1); j++)
if(y[j]<m)
for(int k=1; k<=m-y[j];k++)
if(y[j]+k<y[j+x[i]*k])
y[j+x[i]*k]=y[j]+k;
while(y[r]<maxint) r++;//求得x[1-i]的邮票所能表示的最大连续上界
--r;
if(i>=n)
{
if(r>maxvalue)
{
maxvalue=r;
for(int j=1;j<=n;j++)
bestx[j]=x[j];
}
return;
}
int *z=new int [maxl+1];
for(int k=1;k<=maxl;k++)
z[k]=y[k];
for(j=x[i]+1;j<=r+1;j++)//下一个区间的取值范围从[r+1,...],所以必须保证有值能取到r+1,因为这个区间能取到的最大连续值是r
{
if (y[r+1 - j] < m)
{
x[i+1]=j;
BackTrack(i+1,r);//r代表当前区间能取到的最大连续值
for(k=1;k<=maxl;k++)
y[k]=z[k];
}
}
delete [] z;
}
int MaxStamp(int n, int m, int bestx[])
{
int i;
Stamp X;
int maxint=32767;
int maxl=1500;
X.n=n;
X.m=m;
X.maxvalue=0;
X.maxint=maxint;
X.maxl=maxl;
X.bestx=bestx;
X.x=new int [n+1];
X.y=new int [maxl+1];
for(int i=0;i<=n;i++)
X.x[i]=0;
for(i=1;i<=maxl;i++)
X.y[i]=maxint;
X.x[1]=1;
X.y[0]=0;
X.BackTrack(1,0);//这样取值比王晓东书上的更好理解了,0前一个区间能取到的最大连续值是0,这是因为前一个区间没有任何邮票的面值
delete [] X.x;
delete [] X.y;
return X.maxvalue;
}
int main()
{
int n,m;
// cout<<"请输入邮票面值数(n)和每张信封最多允许贴出的邮票数(m):";
while(scanf("%d%d",&n,&m))
{
int *bestx=new int [n+1];
int maxvalue;
maxvalue=MaxStamp(n,m,bestx);
cout<<"最优解为: ";
for(int i=1;i<=n;i++)
cout<<bestx[i]<<" ";
cout<<"\n"<<"最大连续邮资区间为:"<<maxvalue<<endl;
}
return 0;
}
连续邮资问题
最新推荐文章于 2018-03-04 12:56:54 发布