基础NEH算法 在 流水车间调度问题(FlowShop)问题 的应用(C++)

1 篇文章 0 订阅
1 篇文章 0 订阅

对于流水车间调度问题,基本的NEH不一定能给出最短或者最优的加工序列,但是他可以在一定程度上保证加工序列的局部最优性,所以它通常可以作为一些其他的算法(如IGA)的输入。
以下是启发式方法NEH的简介:
启发式算法利用问题特定知识和经验产生求解方案,能够在较短时间内得到次优解。研究表明,3台以上机器的PFSP即为NP-hard问题,至今没有一个多项式复杂性的全局优化算法。为了快速得到问题的次优解,研究人员提出了若干启发式算法。启发式方法有:Johnson算法、Campleu-Dudek-Smith方法、Palmer方法、Gupta方法、Rapid Access方法、Pour方法、Nawaz-Enscore-Ham方法、NEH_D方法、NEH-KK方法、Rajendran方法、B5Cmax方法、FRB方法等。
由Nawaz M, Enscore JEE, Ham I. 3位作者提出的启发式方法,命名为NEH,是解决 𝐹_𝑚 |𝑝𝑟𝑚𝑢|𝐶_𝑚𝑎𝑥最有效的启发式方法之一。

NEH的大致流程为:
在这里插入图片描述
例如:一个6*3的基础调度问题
在这里插入图片描述
其中行数代表工件的个数,列数代表每一个工件需要加工的步骤数,某行某列填入的数字代表了某个工件在某个步骤的加工权值(时间)
比如:第一行第一列的19表示第一个工件的第一个步骤需要加工19个单位的时间
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在代码中用pai0 来表示结果所对应的加工序列

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>

using namespace std;
int times[105][105]= {{19,46,65},{44,63,12},{85,56,98},{59,68,25},{87,66,53},{51,4,63}};
static int num,prcs;
void InitTime()//初始化时间矩阵
{
    for(int i = 0; i < num; i++)
        for(int j = 0; j < prcs ; j++)
            scanf("%d",&times[i][j]);
}
void PrintSquence(int Paitemp[],int k)//输出调度序列
{
    if(k<=num)
        for(int i = 0; i < k; i++)
            cout<<Paitemp[i]<<" ";
}
void SquenceCopy(int a[],int b[])//复制加工序列
{
    for(int i = 0 ; i < num ; i++)
        a[i] = b[i];
}
void InsSort(int Pai[],int insLoc,int Loc)//插入操作
{
    //加工序列数组   插入的位置  待插入元素的位置
    //{2,1,5,4,3} InsSort(Pai,3,5)   {2,1,3,5,4}
    if(insLoc < Loc)
    {
        int temp = Pai[Loc-1];
        for(int i = Loc-1; i > insLoc-1; i--)
            Pai[i] = Pai[i-1];
        Pai[insLoc-1] = temp;
    }
    else;
}
int CalcuTime(int num,int prcs,int Pai[])//计算加工时间
{

    int pre[prcs] = {0};
    int cur[prcs] = {0};
    int sum = 0;
    for(int i = 0; i < num ; i++)
    {
        for(int j = 0; j < prcs ; j++)
        {

            if(j == 0)
            {
                cur[j] += times[Pai[i]-1][0];
            }
            else
            {
                cur[j] = max(pre[j],cur[j-1]) + times[Pai[i]-1][j];
            }

        }
        sum = cur[prcs-1];
        for(int j = 0; j < prcs ; j++)
            pre[j] = cur[j];
    }

    return sum;
}


int BasicNEH(int num,int prcs,int Pai0[])
{
    int SumFroEach[num] = {0};
    for(int i = 0; i < num; i++)// 对时间矩阵的每一行求和
        for(int j = 0; j < prcs ; j++)
            SumFroEach[i] += times[i][j];
    int Pai[num];
    for(int i = 0; i<num; i++)
        Pai[i] = i+1;
    for(int i = 0; i <num-1; i++)//双向冒泡排序
    {                                      //最大值往左冒的同时,最小值往右冒。比传统的冒泡排序节省一些循环次数
        if(i == num - 1 - i || i == num - i)
            break;
        int    maxsum = SumFroEach[i];
        int    minsum = SumFroEach[num - 1 - i ];
        if(maxsum < minsum)
        {
             swap(SumFroEach[i],SumFroEach[num - 1 - i ]);
             swap(Pai [i], Pai[num - 1 - i ]);
        }
        for(int j = i+1; j < num -1- i ; j++)
        {

            if(SumFroEach[j] > maxsum)
            {
                swap(SumFroEach[j],SumFroEach[i ]);
                maxsum = SumFroEach[i ];
                swap(Pai[j],Pai[i]);
            }
            else if(SumFroEach[j] < minsum)
            {
                swap(SumFroEach[j],SumFroEach[num - 1 - i ]);
                minsum = SumFroEach[num - 1 - i ];
                swap(Pai[j],Pai[  num - 1 - i  ]);
            }
        }
    }
    cout<<endl;//获得排序后的序列
    cout<<"Sorted Sequence is: ";
    PrintSquence(Pai,num);//输出检查一下
    SquenceCopy(Pai0,Pai);//将排序好的加工顺序复制一份
    cout<<endl;
    cout<<endl;
    int presum,sum;//上一次计算的加工时间   本次加工时间
    int Trytime = 1;//记录计算次数
    for(int k = 1 ; k <= num; k++)
    {
        int insLoc = 1,Loc = k;
        for(int j = 0; j <= k-1; j++)
        {
            int Paitemp[num];//建立加工序列副本
            SquenceCopy(Paitemp,Pai);
            if(insLoc < Loc)
            {
                if(j == 0);//第一次不进行插入操作
                else
                    InsSort(Paitemp,insLoc++,Loc);
                printf("Trial NO: %-4d  ",Trytime++);
                sum = CalcuTime(k,prcs,Paitemp);
                if(j == 0)
                    presum = sum;
                else
                {
                    if(sum < presum)
                    {
                        SquenceCopy(Pai0,Paitemp);
                        presum = sum;
                    }
                }

                cout<<"                    Current Sequence : ";
                PrintSquence(Paitemp,k);
                cout<<endl;
                cout<<"Current Procduce Time:        "<<sum<<endl;

                cout<<endl;
            }
            else
                break;

        }
        SquenceCopy(Pai,Pai0);
        cout<<"Result NO: ";
        printf("%-3d :       ",k);
        PrintSquence(Pai0,k);
        cout<<endl<<"*****************************************************"<<endl;

    }
    return presum;
}
int main()
{
    cout<<"Please Input the Numbers And Processes of Each Works "<<endl;
    cout<<"Numbers:  ";
    scanf("%d",&num);
    cout<<"Processes:";
    scanf("%d",&prcs);
    // cout<<"Please Input Time Matrix :"<<endl;
    //InitTime();
    int Pai0[num];
    int sum = BasicNEH(num,prcs,Pai0);
    cout<<"BEH Sequence:";
    PrintSquence(Pai0,num);
    cout<<endl;
    cout<<" MakeSpan: "<<sum<<endl;
    return 0;
}


  • 3
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Liab1l1ty

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

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

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

打赏作者

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

抵扣说明:

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

余额充值