分支界限法 | 装载问题(先入先出队列式分支限界法)

输入要求

有多组数据。
每组数据包含2行。
第一行包含2个整数 C(1 <= C <= 1000)、和 n(1 <= n <= 10),分别表示的轮船的载重量和集装箱的个数。
第二行包含n个整数,依次表示n个集装箱的重量w。(0 <= w <= 1000)

输出要求

对于每组输入数据,按出队次序输出每个结点的信息,包括所在层数,编号,已装载重链,轮船上集装箱的个数
每个结点的信息占一行,如果是叶子结点且其所代表的装上轮船的集装箱的个数大于当前最优值(初始为0),则输出当前最优值 bestv 和最优解 bestx(另占一行)
参见样例输出

测试数据

输入示例

4 3
2 3 2

输出示例

1 1 0 0
2 2 2 1
2 3 0 0
3 5 2 1
3 6 3 1
3 7 0 0
4 10 4 2
bestv=2, bestx=[ 1 0 1 ]
4 11 2 1
4 13 3 1
4 14 2 1
4 15 0 0

小贴士

可采用如下的结构体存储结点:
typedef struct{
    int no; // 结点标号 
    int sw; // 轮船上集装箱的重量 
    int sum; // 轮船上集装箱的数量 
}Node;

#include<stdio.h>
#include<math.h>
 struct Node{
   int no; // ?áμ?±êo?
   int id; //jie dian id
    int sw; // ±3°ü?D???·μ???á?
    int sv; // ±3°ü?D???·μ????μ
};
struct Node queuee[3000];
int w[15],v[15];
int bestv = 0,c,n;
int path[15]; //lu jing
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;

      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) {
					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 + 1;
					queuee[r].sw = node.sw + w[id];
				//	printf("%d %d %d\n",id,v[id], w[id]);

				}
				r++;
				queuee[r].id = node.id+1;
				queuee[r].no = node.no*2 + 1;
				queuee[r].sv = node.sv ;
				queuee[r].sw = node.sw ;
			}

		f++;
	  }

}
int main() {
    while(~scanf("%d %d",&c,&n)){
        for(int i = 1; i <= n; i++) {
            scanf("%d",&w[i]);
            //printf("%d %d\n",w[i], v[i]);
        }
        //printf("%d %d\n",w[2],v[2]);
        branchknap();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/jj81/p/10146498.html

时间: 2024-10-29 03:58:27

分支界限法 | 装载问题(先入先出队列式分支限界法)的相关文章

分支界限法(BFS)

分支界限法类似回溯法,也是在问题的解空间上搜索问题解的算法,其求解目标是找出满足约束条件的一个解(回溯是找出所有的解)或是在满足条件的解中找出最优解. 搜索策略:在扩展结点处,先生成其所有的儿子节点(分支),然后再从当前的活结点表中(根据每一活结点计算出的函数值)选择最有利的结点作为下一个扩展结点. 从活结点表中选择下一扩展结点的不同方式导致不同的分支界限法: 1.队列式(FIFO)分支界限法 2.优先队列式分支界限法 基本思想:以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树.

008-算法-分支界限法

一.概念:与贪婪法一样,这种方法也是用来为组合优化问题设计求解算法的,所不同的是它在问题的整个可能解空间搜索,所设计出来的算法虽然时间复杂度比贪婪算法高,但它的优点是与穷举法类似,都能保证求出问题的最佳解,而且这种方法不是盲目的穷举搜索,而是在搜索中通过界限,可以中途停止对某些不可能得到的最优解的子空间.进一步搜索(类似人工智能中的剪枝),故它比穷举法效率更高. 二.基本思路: 分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树.在分支限界法中,每一个活结点只有一次机会成

五类常见算法小记 (递归与分治,动态规划,贪心,回溯,分支界限法)

近日复习了一些算法知识,小记于此 递归与分治法 直接或间接地调用自身的算法称为递归算法. 递归是算法设计与分析中常用的一种技术,描述简单且易于理解. 分治法的设计思想是将一个规模为n难以解决的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同. 递归地解这些子问题,然后将各子问题的解合并得到原问题的解. 典型例子:Fibonacci数列,阶乘,Hanoi塔:二分法搜索.快速排序.合并排序. 动态规划法 动态规划过程是:根据当前(阶段)状态,采取相应的决策,引起状态的转移.如下图,一

最小重量问题的分支界限法的C++实现方案

*1.问题描述:* *2.解题思路* 这个题目基本思想是 利用分支界限法, 核心就是需要设计一个 优先级标准, 这里我们将 问题的层数,也就是第i个部件作为优先级, 对于相同i的部件,以重量更小的作为优先级的评价标准,然后借助标准库中的优先级队列实现,分支界限法 查找目标. 另外需要注意的是, 使用标准库中的优先级队列时候需要自己重载operator< ,而且一定要有const,233333333 3.源代码 3.1MinMachine.h #pragma once #include <que

第六章-分支界限法

扩展结点:当前结点. 活节点:扩展结点的所有儿子中,经过限界剪枝后剩下的儿子. 分支限界法: 分支:当前扩展结点一次性,产生所有儿子. 限界:在结点扩展的过程中,通过计算结点的上界或下界来大量剪掉树的不合格分支,从而提高搜索效率. 广度优先策略: 一开始,只有根结点是唯一的活结点. 一个活节点一旦成为扩展结点,将一次性产生所有儿子,然后通过"限界"舍弃掉导致不可行解或非最优解的儿子,其余儿子加入活节点表中(队列):然后从活结点表中,弹出队首结点(先进先出)作为当前扩展结点--重复该过程

分治法、动态规划、回溯法、分支界限法、贪心算法

转:http://blog.csdn.net/lcj_cjfykx/article/details/41691787 分治算法一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求解的问题所需的计算时

分支界限法

适用: 要求在某约束条件下,求得由n个元素组成的全部解或最优解(解是个集合) 注意是:它同回溯法解决问题类似,关键的不是在于,这个算法解决的问题,解集合中的元素先后顺序是有影响的: 步骤: 1.把解集合的所有可选元素,整理为树状或图状结构 2.由于解集合元素的先后顺序有关.所以,如果,第m个元素选择后,顺序已然不正确,那么就没有必要继续向深层遍历.基于这一点, 这里应该选择宽度优先遍历 3.如果顺利遍历到最后一个元素,那么表示这是一个解 特别说明: 本算法与回溯法思想相近,由于一个与元素顺序无关

分支界定法详解

分支界定法是求解整数线性规划最优解的经典方法. 定义: 对有约束条件的最优化问题(其可行解为有限数)的所有可行解空间恰当地进行系统搜索,这就是分支与界定的内容.通常把全部解空间反复地分割为越来越小的子集,称为分枝:并对每个子集内的解集计算一个目标下界(对于最小值问题),这称为定界.在每次分枝后,若某个已知可行解集的目标值不能达到当前的界限,则将这个子集舍去.这样,许多子集不予考虑,这称为剪枝.这就是分枝界限法的思路. 背景: 分枝界限法可以用于求解纯整数或混合的整数规划问题.在上世纪六十年代由L

回溯法——装载问题

问题描述: 有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量是wi,且不能超,即Σwi<=c1+c2. 算法思想: --在给定的装载问题有解的情况下 最优装载方案: 首先将第一艘轮船尽可能的装满:  然后将剩余的集装箱装上第二艘轮船. 将第一艘轮船尽可能的装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近c1. 算法设计: 先考虑装载一艘轮船的情况,依次讨论每个集装箱的装载情况,共分为两种,要么装(1),要么不装(0),因此很明显其解空间树可以用子集树