1.基于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);
}
2.基于C语言的银行家算法
实验题目:银行家算法
一、 实验目的
利用银行家算法避免死锁,银行家算法原本是为银行系统设计的,用来保证在发放现金贷款的时候,不会发生不能满足客户需要的情况,在OS中常用银行家算法来避免死锁。
二、 设备与环境
- 设备:PC机
- 环境:C语言编程环境
三、 实验内容
为实现银行家算法,每一个进程在进入系统的时候,他必须申明在运行的过程中,可能需要每种资源类型的最大单元数目,其数目不应超过系统所拥有的资源总量。
四、 实验结果及分析 - 实验设计说明
为了实现银行家算法,在系统中可以设置下面六个数据结构,分别用力啊描述系统中的
(1) Allocation可以存放各个进程以及资源已有的资源数
(2) Max各个进程和各类资源的总需求量
(3) maxres用来存放系统为各类资源提供的最大限度
(4) work表示各类资源已有的资源总量。Work[j] += Allocation[i][j];
(5) need表示还需要的各类资源的数量。Need[i] = maxres[i] - Work[i];
(6) running用来设置标志位 - 实验代码
主函数:
void bank()
{
while (count != 0) //只有存在进程progress,count!=0就成立
{
safe = 0;//设置标志位
for (i = 0; i < progress; i++)
{
if (running[i]) //存在进程progress,running[i]=1,则if条件成立
{
mark = 1;//标志位
for (j = 0; j < variety; j++)
{
if (Max[i][j] - Allocation[i][j] > Need[j])
{//用于判断 需要的资源数是否大于可提供的资源
mark = 0;//满足情况,置0
break;
}
}
if (mark)
{
printf("\n进程%d安全\n", i);//进程从0开始,(i = 0; i < progress; i++)
running[i] = 0;
count--;//控制while(count != 0 ),当count减到0后,跳出while循环
safe = 1;
for (j = 0; j < variety; j++)
{
Need[j] += Allocation[i][j];//已有的资源+释放的资源
}
break;
}
}
}
if (!safe)//经过上述作用,safe值变为1,取反后if条件不成立
{//如果经过一系列判断后,进程都不满足安全状态
printf("\n进程陷入了不安全状态\n");
break;
}
else
{
printf("\n进程是安全的");
printf("\n各类资源的资源总量 :");
for (i = 0; i < variety; i++)
{
printf("\t%d", Need[i]);//输出资源总量
}
printf("\n");
}
}
}
- 实验结果
请输入进程数目:5
请输入资源种类数目: 3
请输入系统为各类资源提供的最大限度 :10 5 7
请输入各个进程和各类资源已有库存 :
0 1 0
2 0 0
3 0 2
2 1 1
0 0 2
请输入各个进程和各类资源的总需求量 :
7 5 3
3 2 2
9 0 2
2 2 2
4 3 3
系统为各类资源提供的最大限度 : 10 5 7
各个进程和各类资源已有库存 :
0 1 0
2 0 0
3 0 2
2 1 1
0 0 2
各个进程和各类资源的总需求量:
7 5 3
3 2 2
9 0 2
2 2 2
4 3 3
目前各类资源已有的资源总量 : 7 2 5
各类资源仍需的资源总量 : 3 3 2
进程1安全
进程是安全的
各类资源的资源总量 : 5 3 2
进程3安全
进程是安全的
各类资源的资源总量 : 7 4 3
进程0安全
进程是安全的
各类资源的资源总量 : 7 5 3
进程2安全
进程是安全的
各类资源的资源总量 : 10 5 5
进程4安全
进程是安全的
各类资源的资源总量 : 10 5 7
4. 实验结果分析
通过键盘输入进程的数目、资源种类数目、各类资源提供的最大限度、个进程和各类资源已有库存、个进程和各类资源的总需求量。然后通过bank()函数来计算各类资源仍需的资源总量,以及判断当前进程是否安全并输出当前各类资源的总量。
五、 实验心得
通过学习和设计银行家算法,了解银行家算法避免死锁的处理原理。死锁问题的出现容易导致进程进入不安全状态,银行家算法的使用,当进程请求一组资源的时候,系统必须确认是否具有足够的资源,以及给他分配资源后,自身进程是否 会陷入不安全状态。