//动态规划解决0-1背包问题
template<class Type>
void Knapsack(Type v,int w,int c,int n,Type **m)
{
int jMax=min(w[n]-1,c);
for(int j=0;j<=jMax;j++)
m[n][j]=0;
for(int j=w[n];j<=c;j++)
m[n][j]=v[n];
for(int i=n-1;i>1;i--)
{
jMax=min(w[i]-1,c);
for(int j=0;j<=jMax;j++)
m[i][j]=m[i+1][j];
for(int j=w[i];j<=c;j++)
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
m[1][c]=m[2][c];
if(c>=w[1])
m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
}
template<class Type>
void Traceback(Type **m,int w,int c,int n,int x)
{
for(int i=1;i<n;i++)
if(m[i][c]==m[i+1][c]) x[i]=0;
else
{
x[i]=1;c-=w[i];
}
x[n]=(m[n][c])?1:0;
}
//回溯法解决0-1背包问题
template<class Typew,class Typep>
class Knap
{
friend Typep Knapsack(Typep*,Typew*,Typew,int);
private:
Typep Bound(int i);
void Backtrack(int i);
Typew c; //背包容量
int n; //物品数
Typew *w; //物品重量数组
Typep *p; //物品价值数组
Typew *cw; //当前重量
Typep cp; //当前价值
Typep bestp; //当前最优价值
};
template<class Typew,class Typep>
void Knap<Typew,Typep>::Backtrack(int i)
{
if(i>n) //到达叶节点
{
bestp=cp;
return;
}
if(cw+w[i]<=c) //进入左子树
{
cw+=w[i];
cp+=p[i];
Backtrack(i+1);
cw-=w[i];
cp-=p[i];
}
if(Bound(i+1)>bestp) //进入右子树
Backtrack(i+1);
}
template<class Typew,class Typep>
Typep Knap<Typew,Typep>::Bound(int i)
{//计算上界
Typew cleft=c-cw; //剩余容量
Typep b=cp;
while(i<=n&&w[i]<=cleft)
{//以物品单位重量价值递减序装入物品
cleft-=w[i];
b+=p[i];
i++;
}
//装满背包
if(i<=n)
b+=p[i]*cleft/w[i];
return b;
}
class Object{
friend int Knapsack(int *,int *,int,int);
public:
int operator<=(Object a)const
{
return (d>=a.d);
}
private:
int ID;
float d;
};
template<class Typew,class Typep>
Typep Knapsack(Typep p[],Type2 w[],Typew c,int n)
{
//为Knap::Backtrack初始化
Typew W=0;
Typep P=0;
Object *Q=new Object[n];
for(int i=1;i<=n;i++)
{
Q[i-1].ID=i;
Q[i-1].d =1.0*p[i]/w[i];
P+=p[i];
W+=w[i];
}
if(W<=c) return P; //装入所有物品
//依物品单位重量价值排序
Sort(Q,n);
Knap<Typew,Typep> K;
K.p=new Typep[n+1];
K.w=new Typew[n+1];
for(int i=1;i<=n;i++)
{
K.p[i]=p[Q[i-1].ID];
K.w[i]=w[Q[i-1].ID];
}
K.cp=0;
K.cw=0;
K.c=c;
K.n=n;
K.bestp=0
//回溯搜索
K.Backtrack(1);
delete []Q;
delete []K.w;
delete []K.p;
return K.bestp;
}
//优先队列式分支界限法解决背包问题
template<class Typew,class Typep> class Knap;
class bbnode{
friend Knap<int,int>;
friend int Knapsack(int *,int *,int,int,int*);
private:
bbnode *parent; //指向父结点的指针
bool LChild; //左儿子结点标志
};
template<class Typew,class Typep>
class HeapNode
{
friend Knap<Typew,Typep>;
public:
operator Typep() const
{
return uprofit;
}
private:
Typep uprofit, //结点的价值上界
profit; //结点所对应的价值
Typew weight; //结点所相应的重量
int level; //活结点在子集树中所处的层次号
bbnode *ptr; //指向活结点在子集树中相应结点的指针
};
template<class Typew,class Typep>
class KKnap
{
friend Typep Knapsack(Typep*,Typew*,Typew,int);
public:
Typep MaxKnapsack();
private:
MaxHeap<HeapNode<Typep,Typew>> *H;
Typep Bound(int i);
void AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int level);
bbnode *E; //指向扩展结点的指针
Typew c; //背包容量
int n; //物品数
Typew *w; //物品重量数组
Typep *p; //物品价值数组
Typew *cw; //当前重量
Typep cp; //当前价值
int *bestx; //最优解
};
template<class Typew,class Typep>
void KKnap<Typep,Typew>::AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev)
{
//将一个新的活结点插入到子集树和最大堆H中
bbnode *b=new bbnode;
b->parent=E;
b->LChild=ch;
HeapNode<Typep,Typew> N;
N.uprofit=up;
N.profit=cp;
N.weight=cw;
N.level=lev;
N.ptr=b;
H->Insert(N);
}
template<class Typew,class Typep>
Typep KKnap<Typew,Typep>::MaxKnapsack()
{
//优先队列式分支界限法,返回最大价值,bestx返回最优解
//定义最大堆的容量为1000
H=new MaxHeap<HeapNode<Typep,Typew>>(1000);
//为bestx分配存储空间
bestx=new int[n+1];
//初始化
int i=1;
E=0;
cw=cp=0;
Typep bestp=0; //当前最优值
Typep up=Bound(1); //价值上界
//搜索子集空间树
while(i!=n+1)
{
//非叶结点
//检查当前扩展结点的左儿子结点
Typew wt=cw+w[i];
if(wt<=c)
{
//左儿子结点为可行结点
if(cp+p[i]>bestp) bestp=cp+p[i];
AddLiveNode(up,cp+p[i],cw+w[i],true,i+1);
}
up=Bound(i+1);
//检查当前扩展结点的右儿子结点
if(up>=bestp)
AddLiveNode(up,cp,cw,false,i+1);
//取下一扩展结点
HeapNode<Typep,Typew> N;
H->DeleteMax(N);
E=N.ptr;
cw=N.weight;
cp=N.profit;
up=N.uprofit;
i=N.level;
}
//构造当前最优解
for(int j=n;j>0;j--)
{
bestx[j]=E->LChild;
E=E->parent;
}
return cp;
}
template<class Typew,class Typep>
Typep Knapsack(Typep p[],Type2 w[],Typew c,int n,int bestx[])
{
//为Knap::Backtrack初始化
Typew W=0;
Typep P=0;
Object *Q=new Object[n];
for(int i=1;i<=n;i++)
{
Q[i-1].ID=i;
Q[i-1].d =1.0*p[i]/w[i];
P+=p[i];
W+=w[i];
}
if(W<=c) return P; //装入所有物品
//依物品单位重量价值排序
Sort(Q,n);
KKnap<Typew,Typep> K;
K.p=new Typep[n+1];
K.w=new Typew[n+1];
for(int i=1;i<=n;i++)
{
K.p[i]=p[Q[i-1].ID];
K.w[i]=w[Q[i-1].ID];
}
K.cp=0;
K.cw=0;
K.c=c;
K.n=n;
K.bestp=0
//调用MaxKnapsack求问题的最优解
Typep bestp=K.MaxKnapsack();
for(int j=1;j<=n;j++)
bestx[Q[j-1].ID]=K.bestx[j];
delete []Q;
delete []K.w;
delete []K.p;
delete []K.bestx;
return bestp;
}