算法设计与分析 项目 工厂开设


1 题目描述

在这里插入图片描述

在这里插入图片描述


2 题目分析及解题思路

2.1 开发环境

  • MATLAB R2016a

由于本题目会使用大量的向量、矩阵操作,为了方便及高效运算,使用MATLAB开发。

2.2 解题思路

2.2.1 解题方法

针对本题目,准备使用三种方法来解,分别是Local Search 顾客选择工厂Local Search 工厂选择顾客模拟退火

2.2.2 编码方式

在使用三种方法解得过程中,编码方式是十分重要的,结合此题目,使用字符串来表示解,形式为:角标对应顾客序号,数组值对应所在工厂序号。
例如解: 1 2 1 3....
代表:1号顾客分配去1号厂;2号顾客分配去2号厂;3号顾客分配去1号厂;4号顾客分配去3号厂…


2.3 Local Search 顾客选择工厂

查看几个算例后发现,其实题目中的例子开设工厂和顾客参与工厂的开销差别不是很大,因此,采取了优先顾客的原则,对于每一位顾客,将他们安排到开销最小的工厂中去,如果该工厂已经满员,那么就安排他去开销第二小的工厂,以此类推。


2.4 Local Search 工厂选择顾客

同样的,如果能够省下工厂的开销,那么也会是一笔不小的数额,因此,采取有限工厂的原则,对于每一个工厂,选择开销最小的顾客直到工厂满员。首先开启第一间工厂,依次选择开销最小的顾客直到满员;之后开启第二间工厂,直到所有的顾客都被安排的明明白白。


2.5 模拟退火算法

在每一轮随机生成新的解,如果生成的新的解比现有的解更好,则接受;否则以一定的概率接受。此概率随着迭代的进行不断减少。
当迭代到一定次数,或连续多次没有接收更加优质的解,视为寻找到最优解。


3 算法实现

3.1 Local Search 顾客选择工厂

FOR i = 1: CustomeNum

WHILE TRUE

FIND_MIN_COST_FACTORY
IF FACTORY_CAPILITY > CUSTOMER_CAPILITY

FACTORY -= CUSTOMER_CAPILITY
BREAK

ENDIF

ENDWHILE

ENDFOR


3.2 Local Search 工厂选择顾客

ARRANGE_NUM = 0;
OPEN_FACTORY = 1;
WHILE ARRANGE != CUSTOMER_NUM

FIND_MIN_COST_CUSTOMER
IF FACTORY_CAPILITY > CUSTOMER_CAPILITY

FACTORY -= CUSTOMER_CAPILITY
RESULT(CUSTOMER) = OPEN_FACTORY
CONTINUE

ENDIF
OPEN_FACTORY++

ENDWHILE


3.3 模拟退火算法

3.3.1 参数设计

由于算例较多,因此设计一套使用所有的参数体系。

参数设计
T(初温)随机生成(顾客数/10)个解,取花费的均值的平方
MIN_T(最低温)T的倒数
FORBID_MAX (最大无用解个数)顾客数 * 工厂数 ^ 2
dropSpeed(降温速率)0.99
INSIDE_NUM(内层循环数)顾客数 * 工厂数
T(初温)随机生成(顾客数/10)个解,取花费的均值的平方

3.3.2 算法

INITIAL(SOLUTION)
WHILE FORBID_NUM < FORBID_MAX && T > MIN_T

FOR i = 1: INSIDE_NUM

NEWSOLUTE = CREATE_NEW_SOLUTION(SOLUTION)
IF ESTIMATE(NEWSOLUTION) < ESTIMATE(SOLUTION)

SOLUTION = NEWSOLUTION
FORBID_NUM = 0

ELSE

RATE = RANDOM(0, 1)
IF RATE < EXP(-DELT(E )/ T)

SOLUTION = NEWSOLUTION

ELSE

FORBID_NUM++

ENDIF

ENDIF

ENDFOR
T *= DROP_SPEED

ENDWHILE


3.3.3 产生新解过程

采取3种新解的方法:

  • 1.随机改变一个顾客所在工厂。
  • 2.随机改变N(N < CUSTOMER_NUM)个顾客所在工厂。
  • 3.随机对任意一段进行排序。

3.3.4 修正解

只修正错误顾客。
从第一位顾客开始记录,当工厂容量不足,将超额的顾客序号记录。
对于超额的顾客,依次安排在剩余未超额的花费最小的工厂中。


3.4 Local Search作为初始的模拟退火算法

与模拟算法类似,但使用了Local Search 的解作为初始解。


4 关键代码

4.1 Local Search 顾客选择工厂

% arrange every customer
for i = 1: cusNum
    while 1
        % find the most adaptor function of this customer
        x = find(tempCus(i, :) == min(tempCus(i, :)));
        x = x(1, 1);
        % function has capiility, arrange; else, put this value to INF
        if tempCap(x, 1) - cusCap(i, 1) > 0
            tempCap(x, 1) = tempCap(x, 1) - cusCap(i, 1);
            result(i, 1) = x;
            break
        else
            tempCus(i, x) = 10000;
        end
    end
end

4.2 Local Search 工厂选择顾客

while 1
    % if all of customer has been arranged
    if currentCus == cusNum
        break;
    end
    % find the most adaptor customer
    x = find(tempCus(:, currentFunc) == min(tempCus(:, currentFunc)));
    x = x(1, 1);
    % if function has capility, arrange customer
    if tempCap(currentFunc, 1) - cusCap(x, 1) > 0
        tempCap(currentFunc, 1) = tempCap(currentFunc, 1) - cusCap(x, 1);
        result(x, 1) = currentFunc;
        tempCus(x, :) = 10000;
        currentCus = currentCus + 1;
        continue;
    end
    % if current function conn't aaccept customer, open a new function
    tempCus(:, currentFunc) = 10000;
    currentFunc = currentFunc + 1
end

4.3 模拟退火算法

4.3.1 主要框架

%外循环
%当温度足够高并且产生的连续废弃解不够多就继续迭代
while T > minT && wrongRes < generateNum
    %内循环
    for i = 1 : cusNum * funcNum
        %生成新解
        newSolu = newSolution( solution, cap, cusCap, cusCost );
        deltaE = estimate( solution, openCost, cusCost ) - estimate( newSolu, openCost, cusCost );
        %新解很好,可以使用,否则一定概率抛弃
        if deltaE > 0
            solution = newSolu;
            wrongRes = 0;
        else 
            %如果低于接受概率,需要抛弃,并增加失败解的数量;否则接受
            randomRate = unifrnd (0,1,1);
            acceptRate = exp(-deltaE / T);
            if randomRate > acceptRate
               solution = newSolu;
               wrongRes = 0;
            else
               wrongRes = wrongRes + 1;
            end
        end
    end
    %降温并记录迭代次数
    T = T * dropSpeed;
    iterateNum = iterateNum + 1;
%     fprintf('iterateNum: %d, solution: %f\n', iterateNum, estimate( solution, openCost, cusCost ));
end

4.3.2 产生新解



4.3.3 修改解

% find all customer who cann't be arrange
for i = 1: cusNum
    tempCap(source(i, 1), 1) = tempCap(source(i, 1), 1) - cusCap(i, 1);
    if tempCap(source(i, 1), 1) < 0
        wrong = [wrong; i];
    end
end

tempCus = cusCost;
% function cann;t accept customer whose capility is minus
for i = 1: funcNum
    if tempCap(i, 1) < 0
        tempCus(:, i) = 10000;
    end
end
% adjust wrong customer location
tempCus = cusCost;
[wrongNum, ~] = size(wrong);
for i = 1: wrongNum
    currentCus = wrong(i, 1);
    while 1
        % find the most adaptor function of this customer
        x = find(tempCus(currentCus, :) == min(tempCus(currentCus, :)));
        x = x(1, 1);
        % function has capiility, arrange; else, put this value to INF
        if tempCap(x, 1) - cusCap(currentCus, 1) > 0
            tempCap(x, 1) = tempCap(x, 1) - cusCap(currentCus, 1);
            result(currentCus, 1) = x;
            break
        else
            tempCus(currentCus, x) = 10000;
        end
    end
end

4.4 其他

4.4.1 数据读取与解析

% read file
data = textread(fileName);

% initial function number and customer number
funcNum = data(1,1);
cusNum = data(1,2);

% initial function capitial and open cost
cap = zeros(funcNum, 1);
openCost = zeros(funcNum, 1);
for i = 1: funcNum
    cap(i, 1) = data(i + 1, 1);
    openCost(i, 1) = data(i + 1, 2);
end

% initial customer capility and cost
rpc = cusNum / 10;
rpf = funcNum / 10;
% get customer capility
cusCap = data(funcNum + 2: funcNum + rpc + 1, :);
% transform and reshape
cusCap = reshape(cusCap', cusNum, 1);

% get customer cost
cusCost = zeros(cusNum, funcNum);
% get data
tempCost = data(funcNum + cusNum / 10 + 2 : funcNum + (cusNum + cusNum * funcNum) / 10 + 1, :);
%reshape
for i = 1: cusNum
    cusCost(i, :) = reshape(tempCost((i - 1) * rpf + 1: i * rpf, :)', funcNum, 1);
end

4.4.2 价值评估

% get cost of customer
for i = 1: m
    cost = cost + cusCost(i, result(i, 1));
end

func = unique(result);
% get open function number
[openFuncNum, ~] = size(func);
% get cost of function
for i = 1: openFuncNum
    cost = cost + openCost(func(i, 1), 1);
end

5 错误数据修改

给出的算例中,p27、p47有严重错误。修改如下:

  • 1.将p27数据后的无用数据全部删除
  • 2.将p47数据的缺失数据用下一行相应位置补齐,如图:

在这里插入图片描述


6 结果分析

6.1 Local Search比较

首先比较两个Local search的结果,很明显的发现,第一种的结果要好于第二种;且两种算法的时间都很短。
在这里插入图片描述
在这里插入图片描述

6.2 LocalSearch与模拟退火比较

很明显的看出,模拟退火需要大量的时间,但是得到的解普遍要优于Local Search。

在这里插入图片描述
在这里插入图片描述

6.3 使用Local Search作为初始解的模拟退火

很明显的发现,用时短了很多,但是得到的解质量却没有随机生成的解好。


7 代码

仓库地址

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值