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

实验名称
优先队列式分支限界法求解0-1背包问题。

实验目的
优先队列式分支限界法求解0-1背包问题,得到不同规模数据实验的时间对比,并进行时间复杂度分析。

实验原理
使用优先队列式的分支限界算法,能准确的找出限定容量背包所能装载的商品的最大价值, 并计算出程序运行所需要的时间。

实验步骤
①根据每个物品的重量和价值计算出物品的单价,根据单价将物品进行排序;
②搜索解空间建立二叉树,从根节点开始;
③广度优先遍历二叉树,并用极大堆表示活结点的优先级,选取扩展结点,找出可行解;
④应当检查左儿子结点是否是可行结点(即上界大于当前最优值且加上该物品的重量不超过背包容量),如果是则将它加入到活结点优先队列中,而当前扩展结点的右儿子一定是可行结点,仅当右儿子满足上界约束时才将它加入到活结点优先队列中;
⑤对优先队列进行堆结构的维护,使得堆顶元素依然是优先级最高的结点;
⑥重复②③④步骤直到优先队列为空,输出结果。

时间复杂度分析
每一个物品都有放入与不放两种决策,求解上界函数的时间复杂度为O(n),因此遍历解空间树的时间复杂度为O(n^2)。

实验心得
通过这次实验,我加深了对分支界限法的学习,同时巩固了随机数据生成方法和文件读写操作的知识。

#include <iostream>
#include <stdio.h>
#include<algorithm>
#include <time.h> 
#include <windows.h>
#include<fstream>
#include<queue>
using namespace std;
ifstream ifile;
ofstream ofile;
int n;
double c;
double bestp = 0.0;//最优价值best price
int bestx[1001];//最优解
struct WP{
	int id;   
	double pre;  
	int v; 
	int w;  
}; 
WP wp[1001]; 

double bound(int i,int cw,int cp)
{   
    double leftw= c-cw;
    double b = cp;
    while(i<=n && wp[i].w<=leftw)
    {
        leftw-=wp[i].w;
        b+=wp[i].v;
        i++;
    }
    if(i<=n)
        b+=wp[i].pre*leftw;
    return b; 
}

bool cmp(WP a,WP b)
{
	return a.pre>b.pre;
}
void init()
{
	ifile>>n>>c;
	for(int i=1;i<=n;i++)
	{
		ifile>>wp[i].w>>wp[i].v;
		wp[i].pre=wp[i].v*1.0/wp[i].w*1.0; 
		wp[i].id=i;
	}
    sort(wp+1,wp+n+1,cmp);
    bestp=0;
} 

struct Node {
	int weight;
	int value;
	int level;
	int x[1001];
	friend bool operator< (Node a, Node b)
	{
		return a.value < b.value;
	}
};

priority_queue<Node> prique;

void enPriQueue(Node pnode, int flag)
{
	Node node;
	node.weight =pnode.weight;
	node.value = pnode.value;
	node.level = pnode.level+1;
	for (int i = 0; i < node.level; i++)
		node.x[i] = pnode.x[i];//把自己父节点的x转移到自己创建的新的x数组里
	node.x[node.level] = flag;//自己结点的x取1还是0,通过传入的flag识别
	if(flag==1){
		node.value+=wp[node.level].v;
		node.weight+=wp[node.level].w;
	} 
	if (node.level == n)//判断是否是叶子结点
	{
		if (node.value > bestp)
		{
			for (int j = 1; j < n + 1; j++)
				bestx[j] = node.x[j];//更新track数组,把叶子结点x数组里记录取不取的值传入track数组中
			bestp = node.value;
		}
		return;
	}
	else
	{
		prique.push(node);//不是叶子结点就入队 
	}
	return;
}
 
int prioritybbnap()
{
	Node liveNode;
	liveNode.weight = 0;
	liveNode.value = 0;
	liveNode.level = 0;
	liveNode.x[0] = 0;//第一层不表示商品取舍信息 
	prique.push(liveNode);//把根结点入优先队列 
	do
	{
		if(bound(liveNode.level+1,liveNode.weight,liveNode.value)>bestp)
		{
			if (liveNode.weight + wp[liveNode.level].w <= c)//是否能进左子树
				enPriQueue(liveNode,1);
			enPriQueue(liveNode,0);//进入右子树
		}
		liveNode = prique.top();//把队列里value最大的赋值给liveNode
		prique.pop();//出队--优先级为背包中价值 
	} while (!prique.empty());//空就停止循环
	return 0;
}
 
int main()
{
	LARGE_INTEGER frequency;
 	double v,beginoftime,endoftime,dt,t;
	//10
	ifile.close();
	ifile.open("10.txt"); 
	cout<<"10 SISE:\n";
	init();
 	QueryPerformanceFrequency(&frequency);
 	v=(double)frequency.QuadPart;
 	QueryPerformanceCounter(&frequency);
    beginoftime=frequency.QuadPart;
	prioritybbnap();
 	QueryPerformanceCounter(&frequency);
    endoftime=frequency.QuadPart;
    dt=(double)(endoftime-beginoftime);
    cout<<bestp; 
    t=dt/v;
	cout<<endl<<"Time is "<<t*1000<<"ms\n";
	//100
	ifile.close();
	ifile.open("100.txt"); 
	cout<<"100 SISE:\n";
	init();
 	QueryPerformanceFrequency(&frequency);
 	v=(double)frequency.QuadPart;
 	QueryPerformanceCounter(&frequency);
    beginoftime=frequency.QuadPart;
	prioritybbnap();
 	QueryPerformanceCounter(&frequency);
    endoftime=frequency.QuadPart;
    dt=(double)(endoftime-beginoftime);
    cout<<bestp; 
    t=dt/v;
	cout<<endl<<"Time is "<<t*1000<<"ms\n";	
	//1000 
		ifile.close();
	ifile.open("1000.txt"); 
	cout<<"1000 SISE:\n";
	init();
 	QueryPerformanceFrequency(&frequency);
 	v=(double)frequency.QuadPart;
 	QueryPerformanceCounter(&frequency);
    beginoftime=frequency.QuadPart;
	prioritybbnap();
 	QueryPerformanceCounter(&frequency);
    endoftime=frequency.QuadPart;
    dt=(double)(endoftime-beginoftime);
    cout<<bestp; 
    t=dt/v;
	cout<<endl<<"Time is "<<t*1000<<"ms\n";
    return 0;
}

#include <iostream>
#include <time.h>
#include <fstream>
using namespace std;//RAND_MAX=32767
int w[1000]={0};
int v[1000]={0};
int c,n;
int Size[4]={10,100,1000};//文件大小
void print(ofstream &outfile,int n,int c)//输出到文件 
{
	outfile<<n<<" "<<c<<endl;
	for(int i=0;i<n;i++)
	{
		outfile<<w[i]<<' '<<v[i]<<endl;
	}
}
int main()
{
    int n=0;
    //ifstream
    ofstream out_10("10.txt"),out_100("100.txt"),out_1000("1000.txt");//输入代查找数据;
    srand(time(NULL));//时间种子
    //生成测试文件
    for(int i=0;i<Size[0];i++) 
	{	
		w[i]=rand()%10+1;//得到[0,10)内的数
		v[i]=rand()%200+1;
	}
    print(out_10,Size[0],20);
    for(int i=0;i<Size[1];i++) 
	{
		w[i]=rand()%10+1;
		v[i]=rand()%200+1;	
	}
    print(out_100,Size[1],20);
    for(int i=0;i<Size[2];i++) 
	{
		w[i]=rand()%10+1;	
		v[i]=rand()%200+1;
	}
    print(out_1000,Size[2],20);
}
 
  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值