【算法】优先队列的分枝限界算法的流水作业调度问题(C++源码)

【算法】优先队列的分枝限界算法的流水作业调度问题(C++源码)

一、任务描述

有一个流水作业调度问题,n=4,a[]={5,10,9,7},b[]={7,5,9,8},请实现基于优先队列的分枝限界算法进行求解。

二、步骤描述

创建一个结构体包含:结点编号,x[i]表示第i步分配作业编号,y[i]=1表示编号为i的作业已经分配,步骤编号,已经分配作业M1的执行时间,已经分配作业M2的执行时间,下界,函数的重载与关系函数,1b越小越优先出队。用bond函数求结点e的限界值。用bfs()求解流水作业调度问题。在主函数中分别调用。

三、运行结果截图

1

四、源代码(C++)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 999999
#define	MAX 5

using namespace std;

//问题表示
int n=4; //作业数
int a[MAX]={0,5,10,9,7};//M1上的执行时间,不用下标0的元素
int b[MAX]={0,7,5,9,8};//M2上的执行时间,不用下标0的元素
//求解结果表示
int bestf=INF;//存放最优调度时间
int bestx[MAX];//存放当前作业最佳调度
int total=1;//结点个数累计

struct NodeType//队列结点类型
{
    int no;//结点编号
    int x[MAX];//x[i]表示第i步分配作业编号
    int y[MAX];//y[i]=1表示编号为i的作业已经分配
    int i;//步骤编号
    int f1;//已经分配作业M1的执行时间
    int f2;//已经分配作业M2的执行时间
    int lb;//下界
    bool operator<(const NodeType &s) const//重载<关系函数
    {
        return lb>s.lb;//lb越小越优先出队
    }
};

void bound(NodeType &e)//求结点e的限界值
{
    int sum=0;
    for(int i=1;i<=n;i++)//扫描所有作业
    {
        if(e.y[i]==0)
        {
            sum+=b[i];//仅累计e.x中还没有分配的作业的b时间
        }
    }
    e.lb=e.f1+sum;
}

void bfs()//求解流水作业调度问题
{
    NodeType e,e1; priority_queue<NodeType> qu;//定义优先队列
    memset(e.x,0,sizeof(e.x));//初始化根结点的x
    memset(e.y,0,sizeof(e.y));//初始化根结点的y
    e.i=0;//根结点
    e.f1=0;
    e.f2=0;
    bound(e);
    e.no=total++;
    qu.push(e);//根结点进队列
    while(!qu.empty())
    {
        e=qu.top();
        qu.pop(); //出队结点e
        if(e.i==n) //达到叶子结点
        {
            if(e.f2<bestf) //比较求最优解
            {
                bestf=e.f2;
                for(int j1=1;j1<=n;j1++)
                {
                    bestx[j1]=e.x[j1];
                }
            }
        }
        e1.i=e.i+1;//扩展分配下一个步骤的作业,对应结点e1
        for(int j=1;j<=n;j++)//考虑所有的n个作业
        {
            if(e.y[j]==1)
            {
                continue;//作业j是否已分配,若已分配,跳过
            }
            for(int i1=1;i1<=n;i1++)//复制e.x得到e1.x
            {
                e1.x[i1]=e.x[i1];
            }
            for(int i2=1;i2<=n;i2++)//复制e.y得到e1.y
            {
                e1.y[i2]=e.y[i2];
            }
            e1.x[e1.i]=j;//为第i步分配作业j
            e1.y[j]=1;//表示作业j已经分配
            e1.f1=e.f1+a[j];//求f1=f1+a[j]
            e1.f2=max(e.f2,e1.f1)+b[j];//求f[i+1]=max(f2[i],f1)+b[j]
            bound(e1);
            if(e1.f2<=bestf)//剪枝,剪去不可能得到更优解的结点
            {
                e1.no=total++;//结点编号增加1
                qu.push(e1);
            }
        }
    }
}

int main()
{
	bfs();
	cout<<"Optimal plan is :"<<endl;
	for(int k=1;k<=n;k++)
    {
        cout<<"The "<<k<<" step is to execute the job is :"<<bestx[k]<<endl;
    }
	cout<<"The total time is :"<<bestf<<endl;
	return 0;
}

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
01问题是指给定一组物品和一个背包,每个物品都有一个重量和一个价值,要求在不超过背包容量的前提下,选择一些物品装进背包,使得背包中物品的总价值最大化。优先队列分支限界法是一种求解01问题的有效算法算法设计如下: 1. 定义一个结构体Item,表示每个物品的重量和价值,以及一个属性valueDensity表示单位重量的价值。 2. 定义一个比较函数cmp,用于将Item结构体按照valueDensity从大到小排序。 3. 定义一个结构体Node,表示每个节点的状态,包括当前节点的价值、重量、剩余价值和剩余重量。 4. 定义一个优先队列priority_queue,用于存储节点,并按照价值从大到小排序。 5. 将初始状态压入优先队列,包括当前节点的价值、重量、剩余价值和剩余重量。 6. 从优先队列中取出一个节点,设为当前节点。 7. 如果当前节点的剩余重量为0,说明已经找到了最优解,返回当前节点的价值。 8. 否则,对当前节点进行扩展,生成两个子节点分别表示选择当前物品和不选择当前物品。计算这两个子节点的价值,重量,剩余价值和剩余重量,并将它们压入优先队列。 9. 重复步骤6~8,直到优先队列为空。 10. 如果在优先队列为空之前找到了最优解,返回该解的价值;否则返回0,表示没有找到最优解。 优先队列分支限界法的时间复杂度在最坏情况下为O(2^n),其中n为物品的数量,但是由于优先队列的存在,实际运行时间会远远小于最坏情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码两年半的练习生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值