连续邮资问题
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;
}
總結
- 上一篇: isnan isinf
- 下一篇: sort qsort的区别