算法設計與分析 項目 工廠開設


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 代碼

倉庫地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章