2023年8月1日发(作者:)

算法分析与设计实验报告

第 7 次实验

姓名

时间

实验名称

6.4上午

学号

地点 四合院

班级

优先队列式分支限界法求解0-1背包问题

通过上机实验,要求掌握优先队列式分支限界法求解0-1背包问题的问题描述、算法设计思想、程序设计。

1、使用优先队列式分支限界法算法,根据不同的输入用例,能准确的输出背包能装的最大价值,并计算出程序运行所需要的时间。

2、分支限界法常以广度优先或最小耗费优先(最大效益优先)方式搜索问题的解空间树, 对于0-1背包问题的解空间树是一个棵子集树。

实验目的

3、在分支限界法中有一个活结点表,活结点表中的每个活结点只有一次机会成为扩实验原理

展结点,一旦成为 扩展结点就一次性产生所有儿子结点,在这些儿子结点中,导致不可行解或导致非最优解的儿子 结点被舍弃,其余儿子结点被加入到活结点表中。

4、为了尽快找到0-1背包问题的解,每次选取下一个活结点成为扩展结点的判断依据是当前情况下 最有可能找到最优解的下一个结点。因此,每次选择扩展结点的方法:当前情况下,在活结点表中 选择活结点的上界,最大的活结点成为当前的扩展结点。

这一过程一直持续到找到所需的解或活结点表为空时为止。

1、定义树结点类bbnode,用于构造子集树,以便计算最优解;定义堆结点类HeapNode,用于定义堆元素类型; 定义最大堆类MaxHeap,用于实现优先队列定义.物品类Object,用于保存物品编号和物品的单位重量价值;定义解决0-1背包问题的主类Knap。

实验步骤

2、设计求解0-1背包问题的主函数Knapsack,在其中对物品以单位价值量排序。

3、设计负责求解0-1背包问题的最优值和最优解函数MaxKnapsack在其中调用计算结点价值上界函数Bound,向子集树和最大堆中插入结点函数AddLiveNode和释放最大堆最大结点的函数DeleteMax,实现优先级队列。

4、输入数据到文件中。

5、添加计算运行时间的代码,计算不同规模数据的运行时间,并将结果输出到output文件中。

6、分析时间复杂度:在最坏的情况下所有的节点都入队,最后一个节点才是最优解,这种情况下时间复杂度是指数阶。最好的情况是只装单位价值最大的物品,其余分支都不符合条件被截去这种情况下时间复杂度是常数时间。但分支限界法本质上还是穷举法,平均时间复杂度仍是指数阶。 关键代码

//物品类

class Object{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

int operator <= (Object a) const{

return (d >= a.d);

}

private:

int ID; //物品编号

float d; //单位重量价值

};

//树结点类

class bbnode{

friend class Knap;

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

private:

bbnode *parent; //指向父节点的指针

int LChild;

};

//堆结点类

class HeapNode{

friend class Knap;

friend class MaxHeap;

public:

operator Typep()const{return uprofit;};

private:

Typep uprofit, //结点的价值上界

profit; //结点所相应的价值

Typew weight; //结点所相应的重量

int level; //活结点在子集树中所处的层序号

bbnode *elemPtr; //指向该活结点在子集树中相应结点的指针

};

//最大堆类

class MaxHeap{

public:

MaxHeap(int maxElem)

{

HeapElem = new HeapNode* [maxElem+1]; //下标为0的保留

capacity = maxElem;

size = 0; }

void InsertMax(HeapNode *newNode);

HeapNode DeleteMax(HeapNode* &N);

private:

int capacity;

int size;

HeapNode **HeapElem;

};

//0-1背包问题的主类

class Knap{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

Typep MaxKnapsack();

private:

MaxHeap *H;

Typep Bound(int i);

void AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level);

bbnode *E; //指向扩展结点的指针

Typew c; //背包容量

int n; //物品总数

Typew *w; //物品重量数组(以单位重量价值降序)

Typep *p; //物品价值数组(以单位重量价值降序)

Typew cw; //当前装包重量

Typep cp; //当前装包价值

int *bestx; //最优解

};

void MaxHeap::InsertMax(HeapNode *newNode)

{

int i = 1;

for (i = ++size; i/2 > 0 && HeapElem[i/2]->uprofit < newNode->uprofit;

i /= 2)

{

HeapElem[i] = HeapElem[i/2];

}

HeapElem[i] = newNode;

}

HeapNode MaxHeap::DeleteMax(HeapNode *&N)

{

if(size >0 ) {

N = HeapElem[1];

int i = 1;

while(i < size)

{

if(((i*2 +1) <= size) && HeapElem[i*2]->uprofit >

HeapElem[i*2 +1]->uprofit)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

{

if(i*2 <= size)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

break;

}

}

if(i < size)

HeapElem[i] = HeapElem[size];

}

size--;

return *N;

}

Typep Knap::MaxKnapsack()

{

H = new MaxHeap(10000);

bestx = new int [n+1];

int i = 1;

E = 0;

cw = 0;

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], 1, i);

}

up = Bound(i + 1);

if(up >= bestp)

AddLiveNode(up, cp, cw, 0, i);

HeapNode* N;

H->DeleteMax(N);

E = N->elemPtr;

cw = N->weight;

cp = N->profit;

up = N->uprofit;

i = N->level + 1;

}

for (int i = n; i > 0; i--)

{

bestx[i] = E->LChild;

E = E->parent;

}

return cp;

}

Typep Knap::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]/w[i] * cleft;

return b;

}

void Knap::AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level)

{

bbnode *b=new bbnode;

b->parent=E;

b->LChild=ch;

HeapNode *N = new HeapNode;

N->uprofit=up; N->profit=cp;

N->weight=cw;

N->level=level;

N->elemPtr=b;

H->InsertMax(N);

}

//Knapsack返回最大价值,最优值保存在bestx

Typep Knapsack(Typew *w, Typep *p, Typew c, int n, int *bestx)

{

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)

{

for(int i =1; i<=n; i++)

{

bestx[i] = p[i];

}

return P;

}

for(int i = 1; i

for(int j = 1; j<= n-i; j++)

{

if(Q[j-1].d < Q[j].d)

{

Object temp = Q[j-1];

Q[j-1] = Q[j];

Q[j] = temp;

}

}

Knap 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];

}

= 0;

= 0;

K.c = c;

K.n = n;

Typep bestp = psack();

for(int i = 1; i<=n; i++)

{

bestx[Q[i-1].ID] = [i];

}

delete [] Q;

delete [] K.w;

delete [] K.p;

delete [] ;

delete [] K.H;

return bestp;

}

1、测试自己输入的小规模数据

测试结果

2、测试随机生成100

3、随机生成1000数据

4、随机生成1000数据

在做本次实验之前,我对分支限界法的原理并不是很理解,经过查看课件及网上查找资料,同时结合自己对回溯法等的理解,我对分支限界法有了一个较好的理解,知道了两种主要的分支限界法及分支限界法如何应用于解01背包问题。在查找资料的过程中,我查看了许多网上的别人的代码实现,结合课本上的代码完成了该实验。通过本次试验,我基本上掌握了优先队列分支限界法解0-1背包问题的原理,同时锻炼了自己动手编写及调试代码的能力,收获实验心得 良多。

实验得分 助教签名

附录:完整代码

#include

#include

#include

#include

using namespace std;

ifstream in("");

ofstream out("");

typedef int Typew;

typedef int Typep;

//物品类

class Object{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

int operator <= (Object a) const{

return (d >= a.d);

}

private:

int ID; //物品编号

float d; //单位重量价值

};

//树结点类

class bbnode{

friend class Knap;

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

private:

bbnode *parent; //指向父节点的指针

int LChild;

};

//堆结点类

class HeapNode{

friend class Knap;

friend class MaxHeap; public:

operator Typep()const{return uprofit;};

private:

Typep uprofit, //结点的价值上界

profit; //结点所相应的价值

Typew weight; //结点所相应的重量

int level; //活结点在子集树中所处的层序号

bbnode *elemPtr; //指向该活结点在子集树中相应结点的指针

};

//最大堆类

class MaxHeap{

public:

MaxHeap(int maxElem)

{

HeapElem = new HeapNode* [maxElem+1]; //下标为0的保留

capacity = maxElem;

size = 0;

}

void InsertMax(HeapNode *newNode);

HeapNode DeleteMax(HeapNode* &N);

private:

int capacity;

int size;

HeapNode **HeapElem;

};

//0-1背包问题的主类

class Knap{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

Typep MaxKnapsack();

private:

MaxHeap *H;

Typep Bound(int i);

void AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level);

bbnode *E; //指向扩展结点的指针

Typew c; //背包容量

int n; //物品总数

Typew *w; //物品重量数组(以单位重量价值降序)

Typep *p; //物品价值数组(以单位重量价值降序)

Typew cw; //当前装包重量 Typep cp; //当前装包价值

int *bestx; //最优解

};

void MaxHeap::InsertMax(HeapNode *newNode)

{

int i = 1;

for (i = ++size; i/2 > 0 && HeapElem[i/2]->uprofit < newNode->uprofit; i /= 2)

{

HeapElem[i] = HeapElem[i/2];

}

HeapElem[i] = newNode;

}

HeapNode MaxHeap::DeleteMax(HeapNode *&N)

{

if(size >0 )

{

N = HeapElem[1];

int i = 1;

while(i < size)

{

if(((i*2 +1) <= size) && HeapElem[i*2]->uprofit >

+1]->uprofit)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

{

if(i*2 <= size)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

break;

}

}

if(i < size)

HeapElem[i] = HeapElem[size];

}

size--;

return *N;

HeapElem[i*2 }

Typep Knap::MaxKnapsack()

{

H = new MaxHeap(10000);

bestx = new int [n+1];

int i = 1;

E = 0;

cw = 0;

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], 1, i);

}

up = Bound(i + 1);

if(up >= bestp)

AddLiveNode(up, cp, cw, 0, i);

HeapNode* N;

H->DeleteMax(N);

E = N->elemPtr;

cw = N->weight;

cp = N->profit;

up = N->uprofit;

i = N->level + 1;

}

for (int i = n; i > 0; i--)

{

bestx[i] = E->LChild;

E = E->parent;

}

return cp;

}

Typep Knap::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]/w[i] * cleft;

return b;

}

void Knap::AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level)

{

bbnode *b=new bbnode;

b->parent=E;

b->LChild=ch;

HeapNode *N = new HeapNode;

N->uprofit=up;

N->profit=cp;

N->weight=cw;

N->level=level;

N->elemPtr=b;

H->InsertMax(N);

}

//Knapsack返回最大价值,最优值保存在bestx

Typep Knapsack(Typew *w, Typep *p, Typew c, int n, int *bestx)

{

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)

{

for(int i =1; i<=n; i++)

{

bestx[i] = p[i];

}

return P; }

for(int i = 1; i

for(int j = 1; j<= n-i; j++)

{

if(Q[j-1].d < Q[j].d)

{

Object temp = Q[j-1];

Q[j-1] = Q[j];

Q[j] = temp;

}

}

Knap 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];

}

= 0;

= 0;

K.c = c;

K.n = n;

Typep bestp = psack();

for(int i = 1; i<=n; i++)

{

bestx[Q[i-1].ID] = [i];

}

delete [] Q;

delete [] K.w;

delete [] K.p;

delete [] ;

delete [] K.H;

return bestp;

}

int main()

{

cout<<"请在文件中输入物品数量、背包容量"<

int N ;

in>>N;

Typew c; //背包容量

in>>c;

int bestx[N+1]; //最优解 int bestp; //最优值

Typep p[N+1];//物品价值

Typew w[N+1];//物品重量

cout<<"在文件中读取的物品总数N = "<< N<<",背包容量C = "<< c<

cout<<"请选择生成数据的规模大小:200请输入1,2000请输入2,20000请输入3"<

int x;

cin>>x;

if(x==1)

{

ofstream in1("");

srand(time(NULL));

int n=200;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

}

cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

else if(x==2)

{

ofstream in1("");

srand(time(NULL));

int n=2000;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

}

cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

else if(x==3)

{

ofstream in1("");

srand(time(NULL));

int n=20000;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

} cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

cout<<"添加完毕后请输入1"<

int m;

cin>>m;

clock_t start,finish;

start=clock();

for (int i = 1; i <= N; i++)

{

in>>w[i];

}

for (int i = 1; i <= N; i++)

{

in>>p[i];

}

cout<<"已在input文件中读取物品重量和价值。"<

bestp = Knapsack(w, p, c, N, bestx);

for (int i = 1; i <= N; i++)

{

if(i ==1 ) out<<"是否选取:";

out<

if(i != N) out<<",";

else

out<

}

out<<"背包最优价值:"<

finish=clock();

out<<"开始时间为:"<

cout<<"结果已生成在文件中"<

system("pause");

return 0;

}

2023年8月1日发(作者:)

算法分析与设计实验报告

第 7 次实验

姓名

时间

实验名称

6.4上午

学号

地点 四合院

班级

优先队列式分支限界法求解0-1背包问题

通过上机实验,要求掌握优先队列式分支限界法求解0-1背包问题的问题描述、算法设计思想、程序设计。

1、使用优先队列式分支限界法算法,根据不同的输入用例,能准确的输出背包能装的最大价值,并计算出程序运行所需要的时间。

2、分支限界法常以广度优先或最小耗费优先(最大效益优先)方式搜索问题的解空间树, 对于0-1背包问题的解空间树是一个棵子集树。

实验目的

3、在分支限界法中有一个活结点表,活结点表中的每个活结点只有一次机会成为扩实验原理

展结点,一旦成为 扩展结点就一次性产生所有儿子结点,在这些儿子结点中,导致不可行解或导致非最优解的儿子 结点被舍弃,其余儿子结点被加入到活结点表中。

4、为了尽快找到0-1背包问题的解,每次选取下一个活结点成为扩展结点的判断依据是当前情况下 最有可能找到最优解的下一个结点。因此,每次选择扩展结点的方法:当前情况下,在活结点表中 选择活结点的上界,最大的活结点成为当前的扩展结点。

这一过程一直持续到找到所需的解或活结点表为空时为止。

1、定义树结点类bbnode,用于构造子集树,以便计算最优解;定义堆结点类HeapNode,用于定义堆元素类型; 定义最大堆类MaxHeap,用于实现优先队列定义.物品类Object,用于保存物品编号和物品的单位重量价值;定义解决0-1背包问题的主类Knap。

实验步骤

2、设计求解0-1背包问题的主函数Knapsack,在其中对物品以单位价值量排序。

3、设计负责求解0-1背包问题的最优值和最优解函数MaxKnapsack在其中调用计算结点价值上界函数Bound,向子集树和最大堆中插入结点函数AddLiveNode和释放最大堆最大结点的函数DeleteMax,实现优先级队列。

4、输入数据到文件中。

5、添加计算运行时间的代码,计算不同规模数据的运行时间,并将结果输出到output文件中。

6、分析时间复杂度:在最坏的情况下所有的节点都入队,最后一个节点才是最优解,这种情况下时间复杂度是指数阶。最好的情况是只装单位价值最大的物品,其余分支都不符合条件被截去这种情况下时间复杂度是常数时间。但分支限界法本质上还是穷举法,平均时间复杂度仍是指数阶。 关键代码

//物品类

class Object{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

int operator <= (Object a) const{

return (d >= a.d);

}

private:

int ID; //物品编号

float d; //单位重量价值

};

//树结点类

class bbnode{

friend class Knap;

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

private:

bbnode *parent; //指向父节点的指针

int LChild;

};

//堆结点类

class HeapNode{

friend class Knap;

friend class MaxHeap;

public:

operator Typep()const{return uprofit;};

private:

Typep uprofit, //结点的价值上界

profit; //结点所相应的价值

Typew weight; //结点所相应的重量

int level; //活结点在子集树中所处的层序号

bbnode *elemPtr; //指向该活结点在子集树中相应结点的指针

};

//最大堆类

class MaxHeap{

public:

MaxHeap(int maxElem)

{

HeapElem = new HeapNode* [maxElem+1]; //下标为0的保留

capacity = maxElem;

size = 0; }

void InsertMax(HeapNode *newNode);

HeapNode DeleteMax(HeapNode* &N);

private:

int capacity;

int size;

HeapNode **HeapElem;

};

//0-1背包问题的主类

class Knap{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

Typep MaxKnapsack();

private:

MaxHeap *H;

Typep Bound(int i);

void AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level);

bbnode *E; //指向扩展结点的指针

Typew c; //背包容量

int n; //物品总数

Typew *w; //物品重量数组(以单位重量价值降序)

Typep *p; //物品价值数组(以单位重量价值降序)

Typew cw; //当前装包重量

Typep cp; //当前装包价值

int *bestx; //最优解

};

void MaxHeap::InsertMax(HeapNode *newNode)

{

int i = 1;

for (i = ++size; i/2 > 0 && HeapElem[i/2]->uprofit < newNode->uprofit;

i /= 2)

{

HeapElem[i] = HeapElem[i/2];

}

HeapElem[i] = newNode;

}

HeapNode MaxHeap::DeleteMax(HeapNode *&N)

{

if(size >0 ) {

N = HeapElem[1];

int i = 1;

while(i < size)

{

if(((i*2 +1) <= size) && HeapElem[i*2]->uprofit >

HeapElem[i*2 +1]->uprofit)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

{

if(i*2 <= size)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

break;

}

}

if(i < size)

HeapElem[i] = HeapElem[size];

}

size--;

return *N;

}

Typep Knap::MaxKnapsack()

{

H = new MaxHeap(10000);

bestx = new int [n+1];

int i = 1;

E = 0;

cw = 0;

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], 1, i);

}

up = Bound(i + 1);

if(up >= bestp)

AddLiveNode(up, cp, cw, 0, i);

HeapNode* N;

H->DeleteMax(N);

E = N->elemPtr;

cw = N->weight;

cp = N->profit;

up = N->uprofit;

i = N->level + 1;

}

for (int i = n; i > 0; i--)

{

bestx[i] = E->LChild;

E = E->parent;

}

return cp;

}

Typep Knap::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]/w[i] * cleft;

return b;

}

void Knap::AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level)

{

bbnode *b=new bbnode;

b->parent=E;

b->LChild=ch;

HeapNode *N = new HeapNode;

N->uprofit=up; N->profit=cp;

N->weight=cw;

N->level=level;

N->elemPtr=b;

H->InsertMax(N);

}

//Knapsack返回最大价值,最优值保存在bestx

Typep Knapsack(Typew *w, Typep *p, Typew c, int n, int *bestx)

{

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)

{

for(int i =1; i<=n; i++)

{

bestx[i] = p[i];

}

return P;

}

for(int i = 1; i

for(int j = 1; j<= n-i; j++)

{

if(Q[j-1].d < Q[j].d)

{

Object temp = Q[j-1];

Q[j-1] = Q[j];

Q[j] = temp;

}

}

Knap 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];

}

= 0;

= 0;

K.c = c;

K.n = n;

Typep bestp = psack();

for(int i = 1; i<=n; i++)

{

bestx[Q[i-1].ID] = [i];

}

delete [] Q;

delete [] K.w;

delete [] K.p;

delete [] ;

delete [] K.H;

return bestp;

}

1、测试自己输入的小规模数据

测试结果

2、测试随机生成100

3、随机生成1000数据

4、随机生成1000数据

在做本次实验之前,我对分支限界法的原理并不是很理解,经过查看课件及网上查找资料,同时结合自己对回溯法等的理解,我对分支限界法有了一个较好的理解,知道了两种主要的分支限界法及分支限界法如何应用于解01背包问题。在查找资料的过程中,我查看了许多网上的别人的代码实现,结合课本上的代码完成了该实验。通过本次试验,我基本上掌握了优先队列分支限界法解0-1背包问题的原理,同时锻炼了自己动手编写及调试代码的能力,收获实验心得 良多。

实验得分 助教签名

附录:完整代码

#include

#include

#include

#include

using namespace std;

ifstream in("");

ofstream out("");

typedef int Typew;

typedef int Typep;

//物品类

class Object{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

int operator <= (Object a) const{

return (d >= a.d);

}

private:

int ID; //物品编号

float d; //单位重量价值

};

//树结点类

class bbnode{

friend class Knap;

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

private:

bbnode *parent; //指向父节点的指针

int LChild;

};

//堆结点类

class HeapNode{

friend class Knap;

friend class MaxHeap; public:

operator Typep()const{return uprofit;};

private:

Typep uprofit, //结点的价值上界

profit; //结点所相应的价值

Typew weight; //结点所相应的重量

int level; //活结点在子集树中所处的层序号

bbnode *elemPtr; //指向该活结点在子集树中相应结点的指针

};

//最大堆类

class MaxHeap{

public:

MaxHeap(int maxElem)

{

HeapElem = new HeapNode* [maxElem+1]; //下标为0的保留

capacity = maxElem;

size = 0;

}

void InsertMax(HeapNode *newNode);

HeapNode DeleteMax(HeapNode* &N);

private:

int capacity;

int size;

HeapNode **HeapElem;

};

//0-1背包问题的主类

class Knap{

friend Typep Knapsack(Typew *, Typep *, Typew, int, int *);

public:

Typep MaxKnapsack();

private:

MaxHeap *H;

Typep Bound(int i);

void AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level);

bbnode *E; //指向扩展结点的指针

Typew c; //背包容量

int n; //物品总数

Typew *w; //物品重量数组(以单位重量价值降序)

Typep *p; //物品价值数组(以单位重量价值降序)

Typew cw; //当前装包重量 Typep cp; //当前装包价值

int *bestx; //最优解

};

void MaxHeap::InsertMax(HeapNode *newNode)

{

int i = 1;

for (i = ++size; i/2 > 0 && HeapElem[i/2]->uprofit < newNode->uprofit; i /= 2)

{

HeapElem[i] = HeapElem[i/2];

}

HeapElem[i] = newNode;

}

HeapNode MaxHeap::DeleteMax(HeapNode *&N)

{

if(size >0 )

{

N = HeapElem[1];

int i = 1;

while(i < size)

{

if(((i*2 +1) <= size) && HeapElem[i*2]->uprofit >

+1]->uprofit)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

{

if(i*2 <= size)

{

HeapElem[i] = HeapElem[i*2];

i = i*2;

}

else

break;

}

}

if(i < size)

HeapElem[i] = HeapElem[size];

}

size--;

return *N;

HeapElem[i*2 }

Typep Knap::MaxKnapsack()

{

H = new MaxHeap(10000);

bestx = new int [n+1];

int i = 1;

E = 0;

cw = 0;

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], 1, i);

}

up = Bound(i + 1);

if(up >= bestp)

AddLiveNode(up, cp, cw, 0, i);

HeapNode* N;

H->DeleteMax(N);

E = N->elemPtr;

cw = N->weight;

cp = N->profit;

up = N->uprofit;

i = N->level + 1;

}

for (int i = n; i > 0; i--)

{

bestx[i] = E->LChild;

E = E->parent;

}

return cp;

}

Typep Knap::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]/w[i] * cleft;

return b;

}

void Knap::AddLiveNode(Typep up, Typep cp, Typew cw, int ch, int level)

{

bbnode *b=new bbnode;

b->parent=E;

b->LChild=ch;

HeapNode *N = new HeapNode;

N->uprofit=up;

N->profit=cp;

N->weight=cw;

N->level=level;

N->elemPtr=b;

H->InsertMax(N);

}

//Knapsack返回最大价值,最优值保存在bestx

Typep Knapsack(Typew *w, Typep *p, Typew c, int n, int *bestx)

{

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)

{

for(int i =1; i<=n; i++)

{

bestx[i] = p[i];

}

return P; }

for(int i = 1; i

for(int j = 1; j<= n-i; j++)

{

if(Q[j-1].d < Q[j].d)

{

Object temp = Q[j-1];

Q[j-1] = Q[j];

Q[j] = temp;

}

}

Knap 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];

}

= 0;

= 0;

K.c = c;

K.n = n;

Typep bestp = psack();

for(int i = 1; i<=n; i++)

{

bestx[Q[i-1].ID] = [i];

}

delete [] Q;

delete [] K.w;

delete [] K.p;

delete [] ;

delete [] K.H;

return bestp;

}

int main()

{

cout<<"请在文件中输入物品数量、背包容量"<

int N ;

in>>N;

Typew c; //背包容量

in>>c;

int bestx[N+1]; //最优解 int bestp; //最优值

Typep p[N+1];//物品价值

Typew w[N+1];//物品重量

cout<<"在文件中读取的物品总数N = "<< N<<",背包容量C = "<< c<

cout<<"请选择生成数据的规模大小:200请输入1,2000请输入2,20000请输入3"<

int x;

cin>>x;

if(x==1)

{

ofstream in1("");

srand(time(NULL));

int n=200;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

}

cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

else if(x==2)

{

ofstream in1("");

srand(time(NULL));

int n=2000;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

}

cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

else if(x==3)

{

ofstream in1("");

srand(time(NULL));

int n=20000;

int *a=new int[n];

for(int i=0;i

{

a[i]=rand()%91;

in1<

} cout<<"随机数已请生成到input1文件中,请将数据添加到文件中"<

}

cout<<"添加完毕后请输入1"<

int m;

cin>>m;

clock_t start,finish;

start=clock();

for (int i = 1; i <= N; i++)

{

in>>w[i];

}

for (int i = 1; i <= N; i++)

{

in>>p[i];

}

cout<<"已在input文件中读取物品重量和价值。"<

bestp = Knapsack(w, p, c, N, bestx);

for (int i = 1; i <= N; i++)

{

if(i ==1 ) out<<"是否选取:";

out<

if(i != N) out<<",";

else

out<

}

out<<"背包最优价值:"<

finish=clock();

out<<"开始时间为:"<

cout<<"结果已生成在文件中"<

system("pause");

return 0;

}