基于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语言的分支限界法的主要内容,如果未能解决你的问题,请参考以下文章