分支界限法 | 0-1背包问题(优先队列式分支限界法)

 

 

 

 

 

 

 

 输入要求

有多组数据。
每组数据包含2部分。
第一部分包含两个整数C (1 <= C <= 10000)和 n (1 <= n <= 10,分别表示背包的容量和物品的个数。
第二部分由n行数据,每行包括2个整数 wi(0< wi <= 100)和 vi(0 < vi <= 100),分别表示第i个物品的总量和价值

输出要求

对于每组输入数据,按出队次序输出每个结点的信息,包括所在层数,编号,背包中物品重量和价值。
每个结点的信息占一行,如果是叶子结点且其所代表的背包中物品价值大于当前最优值(初始为0),则输出当前最优值 bestv 和最优解 bestx(另占一行)
参见样例输出

测试数据

输入示例
5 3
2 2
3 2
2 3
输出示例
1 1 0 0
2 2 2 2
3 5 2 2
4 10 4 5
bestv=5, bestx=[ 1 0 1 ]
4 11 2 2
3 4 5 4
2 3 0 0

小贴士

可采用如下的结构体存储结点:
typedef struct{
    int no; // 结点在堆中的标号 
    int sw; // 背包中物品的重量 
    int sv; // 背包中物品的价值 
    double prior; // 优先值 sv/sw 
}Node;

 

  

#include<stdio.h>
#include<math.h>
#include<string.h>
typedef struct {
    int no; // 结点标号 
    int id; // 节点id 
    int sw; // 背包中物品的重量 
    int sv; // 背包中物品的价值 
    double prior; //   sv/sw 
}Node;

int surplusValue(int *v,int n,int y) {
	int sum = 0;
	for(int i = y; i <= n; i++) {
		sum += v[i];
	}
	
	return sum;
}

void qsort(Node *que,int l,int r) {
	int len = r - l + 1;
	int flag;
	
	for(int i = 0; i < len; i ++) {
		flag = 0;
		for(int j = l; j < l + len - i; j++) {
			if(que[j].prior < que[j+1].prior) {
				Node t = que[j];
				que[j] = que[j+1];
				que[j+1] = t;
				flag = 1;
			}
		}
		//if(!flag ) return;
	}
}
 
 void branchknap(int *w,int *v,int c,int n) {
 	int bestv = 0;
	int f = 0;
	int r = 0;
	Node que[3000];
	memset(que,0,sizeof(que));
	int path[15];
	que[0].no = 1;
	que[0].id = que[0].sv = que[0].sw = que[0].prior = 0;
 
 	while(f <= r) {
 		Node node = que[f];
 		printf("%d %d %d %d\n",node.id+1,node.no,node.sw,node.sv);
 		
 		if(node.no >= pow(2,n)) {
 			if(node.sv > bestv) {
 				bestv = node.sv;
 				printf("bestv=%d, bestx=[",bestv);
      			int temp = node.no;
				int i = 0;
				while(temp > 1) {
					if(temp % 2 == 0)
						path[i] = 1;
					else 
						path[i] = 0;
					temp /= 2;
					i++ ;
				}
				i--;
				while(i >= 0) {
					printf(" %d",path[i]);
					i--;
				}
				printf(" ]\n");
			 }
		 } else {
		 	if((node.sw + w[node.id + 1]) <= c && surplusValue(v,n,node.id+1) + node.sv > bestv) {
		 		r++;
		 		que[r].id = node.id + 1;
		 		que[r].no = node.no*2;
		 		int id = node.id + 1;
		 		que[r].sv = node.sv + v[id];
		 		que[r].sw = node.sw + w[id];
		 		que[r].prior = que[r].sv / (que[r].sw*1.0);
			 }
			 
			 if(surplusValue(v,n,node.id+2) + node.sv > bestv) {
			 	r++;
			 	que[r].id = node.id + 1;
			 	que[r].no = node.no*2 + 1;
			 	que[r].sv = node.sv;
			 	que[r].sw = node.sw;
			 	que[r].prior = node.prior;
			 }
		 }
		 f++;
		 qsort(que,f,r);
	 }
 	
 }
 
 int main() {
 	int c,n;
 	int w[15],v[15];	
    while(~scanf("%d %d",&c,&n)){
		 
        for(int i = 1; i <= n; i++) {
            scanf("%d %d",&w[i],&v[i]);                  
        }
        
        branchknap(w,v,c,n);
    }
    return 0;
}

  

#include<stdio.h>
#include<math.h>
#include<string.h>
typedef int bool;
#define true 1
#define false 0

struct Node{
   int no; // ?áμ?±êo? 
   int id; //jie dian id
    int sw; // ±3°ü?D???·μ???á? 
    int sv; // ±3°ü?D???·μ????μ 
    double prior;
};
struct Node queuee[2000];
int w[15],v[15];
int bestv = 0,c,n;
int path[15]; //lu jing


int surplusValue(int y) {
	int sum = 0;
	for(int i = y; i <= n; i++)
		sum += v[i];
		
	return sum;
}
void qsort(int l,int r) {
	
//	printf("------\n"); 
	int len = r - l + 1;
	//printf("----%d %d %d-----\n",l,r,len);
	bool flag;
	for(int i = 0; i < len  ; i++) {
		flag = false;
		for(int j = l; j <l+ len -i  ;j++) {
			if(queuee[j].prior < queuee[j+1].prior) {
				struct Node temp = queuee[j];
				queuee[j] = queuee[j+1];
				queuee[j+1] = temp;
				flag = true;
			}
			//if(!flag) return;
		}
	}

//	printf("---排序嘻嘻---\n"); 
	//for(int i = l; i <= r;i++ )
	//	printf("***%d : %.2lf\n",queuee[i].no,queuee[i].prior);
//	printf("\n------\n"); 
} 

void branchknap() {
      bestv = 0;
      int f = 0;
      int r = 0;
      queuee[0].no = 1;
      queuee[0].id = 0;
      queuee[0].sv = 0;
      queuee[0].sw = 0;
      queuee[0].prior = 0;
    //  printf("f: %d r: %d\n",f,r);
      while(f <= r) {
      		struct Node node = queuee[f];
      		printf("%d %d %d %d\n",node.id+1,node.no,node.sw,node.sv);
      		
      		if(node.no >= pow(2,n)) {
      			if(node.sv > bestv) {
      				bestv = node.sv;
      				
      				//TODO 
      				printf("bestv=%d, bestx=[",bestv);
      				int temp = node.no;
					int i = 0;
      				while(temp > 1) {
      					if(temp%2 == 0) 	
      						path[i] = 1;
      					else
      						path[i] = 0;
      					temp /= 2;
      					i++;
					}
					i--;
					while(i >= 0) {
						printf(" %d",path[i]);
						i--;
					}
					printf(" ]\n");
      				
				  } 
			} else {
				
				if((node.sw + w[node.id+1]) <= c && surplusValue(node.id+1) + node.sv > bestv) {
					r++;
					//printf("%d\n",(node.sw + w[node.id+1]));
					queuee[r].id = node.id+1;
					queuee[r].no = node.no*2;
					int id = node.id+1;
					queuee[r].sv = node.sv + v[id];
					queuee[r].sw = node.sw + w[id];
					queuee[r].prior = queuee[r].sv/(queuee[r].sw*1.0);
					
						//printf("进队id: %d\n",queuee[r].no) ;
					
						
					//printf("%d %d %d\n",id,v[id], w[id]);
					
				} 
			
				if(surplusValue(node.id+2) + node.sv > bestv) {
					r++;
					queuee[r].id = node.id+1;
					queuee[r].no = node.no*2 + 1;
					queuee[r].sv = node.sv ;
					queuee[r].sw = node.sw ;
					queuee[r].prior = node.prior;
					//printf("进队id: %d\n",queuee[r].no) ;
				}
				
			}
			
		f++;
		qsort(f,r);
	  }
      
      
}
int main() {
    while(~scanf("%d %d",&c,&n)){
    	memset(queuee,0,sizeof(queuee));
        for(int i = 1; i <= n; i++) {
            scanf("%d %d",&w[i],&v[i]);
        }
        
        branchknap();
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/jj81/p/10146555.html

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
0/1背包问题是一个经典的组合优化问题,分支限界法是一种常用的解决此类组合优化问题的算法。 以下是使用分支限界法实现0/1背包问题的步骤: 1. 定义节点。节点是指问题的一个状态,包括已经选取的物品和剩余可选物品。 2. 定义扩展操作。扩展操作是指从一个节点扩展出子节点的过程,即在当前节点的基础上添加一个物品或不添加物品。 3. 定义界限函数。界限函数是指一个节点的最大可行价值上界,用于判断是否需要继续探索该节点。 4. 定义优先队列优先队列是指用于存储节点的数据结构,按照节点的界限函数值从小到大排序,每次取出优先队列的最小值进行扩展操作。 5. 对于每个节点,如果当前的可行价值已经超过当前最优解,则不再进行扩展操作。 6. 最终得到的最优解即为问题的最优解。 以下是示例代码实现: ```python class Node: def __init__(self, profit, weight, bound, level): self.profit = profit self.weight = weight self.bound = bound self.level = level def __lt__(self, other): return self.bound < other.bound def bound(node, capacity, values, weights): if node.weight >= capacity: return 0 else: bound = node.profit j = node.level + 1 totweight = node.weight while j < len(values) and totweight + weights[j] <= capacity: bound += values[j] totweight += weights[j] j += 1 if j < len(values): bound += (capacity - totweight) * values[j] / weights[j] return bound def knapsack_bfs(capacity, values, weights): n = len(values) queue = [] root = Node(0, 0, 0, -1) queue.append(root) maxprofit = 0 while queue: node = queue.pop(0) if node.level == n - 1: continue if node.weight + weights[node.level + 1] <= capacity: leftnode = Node(node.profit + values[node.level + 1], node.weight + weights[node.level + 1], 0, node.level + 1) if leftnode.profit > maxprofit: maxprofit = leftnode.profit queue.append(leftnode) rightnode = Node(node.profit, node.weight, 0, node.level + 1) rightnode.bound = bound(rightnode, capacity, values, weights) if rightnode.bound > maxprofit: queue.append(rightnode) return maxprofit values = [10, 40, 30, 50] weights = [5, 4, 6, 3] capacity = 10 print(knapsack_bfs(capacity, values, weights)) ``` 输出结果为90,表示在背包容量为10时,物品的最大价值为90。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值