基于C语言的分支限界法

Posted Mr.zhou_Zxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于C语言的分支限界法相关的知识,希望对你有一定的参考价值。

/* 采用分支限界法解决集装箱问题:
问题:有n个集装箱要装上一艘载重量为W的轮船,其中集装箱i(1≤i≤n)的重量为wi。
在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船,当总重量相同时要
求选取的集装箱个数尽量少。编写一个实验程序采用分枝限界法求解,设计合理的限
界函数,并采用队列式分支限界法求最优解。其中,n=5,W=10,w={5,2,6,4,3}
集装箱个数:n;
轮船可承载重量:W;
集装箱i的重量wi;
思路:
1.对于第i层的结点e,已装载的集装箱的总重量为e.w,剩余集装箱重量为r, 定义结点e的上届函数为e.w+r.
2.对于左孩子结点,当满足e.w+w[e.i+1]>W时会变成死结点,对于e结点的右孩子节点,其上界最优解的装载重量maxw,被剪枝
3.在队列基本运算中,函数对队列进行初始化判断,以及判空操作,结点的进队操作
4.在分支限界法操作过程中,实现记录分支结点的上界,计算并输出最优解。
5.队列式分支限界法,建立队列,并采用先进先出的原则,选择下一个结点作为拓展结点
*/

#include<stdio.h>//主函数 
#define MAXN 20//最多集装箱数 
#define MAXQ 50//队列大小 
int maxw = 0;//全局变量,存放最大装载重量 
int maxx[MAXN] = {0};//全局变量,存放最优解  
int count = 1;//全局变量,累计节点数 
typedef struct
{
	int no;
	int i;
	int w;
	int x[MAXN];
	int ub;
}ElemType;//队列结点类型定义 
typedef struct
{
	ElemType data[MAXQ];
	int front,rear;
}QueueType;//队列类型 
void copyx(int x[],int y[],int i)//实现解向量复制功能 
{
	int j;
	for(j=0;j<=i;j++)
		y[j]=x[j];
}
void elemcopy(ElemType a,ElemType &b)//队列结点复制 
{
	b.no=a.no;b.i=a.i;
	b.ub=a.ub;b.w=a.w;
	copyx(a.x,b.x,a.i);//调用void copyx() 
}
void initQueue(QueueType &q)//队列初始化 
{
	q.front=q.rear=0;//头结点等于尾结点等于零 
}
int emptyQueue(QueueType q)//判空操作
{
	return q.front==q.rear;//头结点与尾结点在同一位置 
}
int enQueue(QueueType &q,ElemType e,int n)//进队操作 
{
	if((q.rear+1)%MAXQ==q.front)//判断队是否为满 
		return 0;
	else//可进队 
	{
		if(e.i==n)//可行叶子结点,不进队 
		{
			if(e.w>maxw||(e.w==maxw&&e.x[0]<maxx[0]))//比较找最优解 
			{maxw=e.w;
			copyx(e.x,maxx,n);
		}
		
		}
		else//其他结点进队 
		{
			q.rear=(q.rear+1)%MAXQ;
			elemcopy(e,q.data[q.rear]);
		}
		return 1;
	}
}
int deQueue(QueueType &q,ElemType &e)//结点e出队 
{
	if(emptyQueue(q))//调用判空函数 
		return 0;
	else
	{
		q.front=(q.front+1)%MAXQ;
		elemcopy(q.data[q.front],e);
		return 1;
	}
}
void bound(int w[],int W,int n,ElemType &e)//计算分支结点e的上界 
{
	int i=e.i+1;
	int r=0;//剩余集装箱重量 
	while(i<=n)
	{
		r+=w[i];
		i++;
	}
	e.ub=e.w+r;
	
}
void Loading(int w[],int W,int n)//采用队列式分支限界法求解装载问题的最优解 
{
	int j;
	QueueType q;//建立一个队列 
	initQueue(q);//队列初始化 
	ElemType e,e1,e2;//定义三个结点 
	e.i=0;
	e.w=0;
	e.no=count++;
	for(j=0;j<=n;j++)
		e.x[j]=0;
		bound(w,W,n,e);//求根结点的上界 
		enQueue(q,e,n);//根节点进队 
		while(!emptyQueue(q))//判空操作 
		{
			deQueue(q,e);
			if(e.w+w[e.i+1]<=W)
			{
				e1.no=count++;
				e1.i=e.i+1;//建立左孩子结点 
				e1.w=e.w+w[e1.i];
				copyx(e.x,e1.x,e.i);
				e1.x[0]++;//装入集装箱数增1 
				e1.x[e1.i]=1;
				bound(w,W,n,e1);//求左孩子结点的上界 
				enQueue(q,e1,n); 
			 } 
			 e2.no=count++;
			 e2.i=e.i+1;//建立右孩子结点 
			 e2.w=e.w;
			 copyx(e.x,e2.x,e.i);
			 e2.x[e2.i]=0;
			 bound(w,W,n,e2);//求右孩子结点的上界 
			 if(e2.ub>maxw)//若右孩子结点可行,则进队,否则被剪枝 
			 	enQueue(q,e2,n);
		}
 } 
 void dispasolution(int n)//输出最优解 
 {
 	int i;
 	printf("采用分支限界法求解装载问题:\\n");
	 printf("共装入%d个集装箱\\n",maxx[0]);
	 printf("X=[");
	 for(i=1;i<=n;i++)
	 	printf("%2d",maxx[i]);
	printf("]\\n装载总重量为%d\\n",maxw); 
 }
 int main()//主函数 
 {
 	int n=5,W=10;
 	int w[]={0,5,2,6,4,3};//各个集装箱的重量 
 	Loading(w,W,n);//调用分支限界法求装载问题 
 	dispasolution(n);//输出最优解 
 	printf("搜索的结点个数为%d\\n",count);
 }

以上是关于基于C语言的分支限界法的主要内容,如果未能解决你的问题,请参考以下文章

分支限界法C++ 学习&练习

分支限界法C++ 学习&练习

分支限界法C++ 学习&练习

分支限界法C++ 学习&练习

c_cpp 【分支限界法】批处理作业调度

c_cpp 【分支限界法】最大团问题【6.6】