題目描述
Suppose there are n facilities and m customers. We wish to choose:
(1) which of the n facilities to open
(2) the assignment of customers to facilities
The objective is to minimize the sum of the opening cost and the assignment cost.
The total demand assigned to a facility must not exceed its capacity.
解題思路
首先解析一下題目的意思。假設(shè)某地有n個(gè)可以開的工廠,m個(gè)顧客,每個(gè)工廠的開設(shè)都要不同的費(fèi)用,而顧客為了滿足自身的需求,到不同的工廠去消費(fèi)也要不同的費(fèi)用?,F(xiàn)在需要找出,在滿足了所有顧客的需求的情況下,最小的費(fèi)用。這里要注意,每家工廠都有自己的容量,不可以無限制的滿足顧客的需求,若一個(gè)工廠剩余的容量比某個(gè)顧客的需求要小,那么它是無法滿足顧客的需求;而對于顧客而言,他只能去一家工廠滿足自己的需求。
先來分析一下這里的約束條件。首先是工廠的開設(shè)費(fèi)用,每個(gè)工廠的開設(shè)都是需要一定費(fèi)用的;然后是顧客到工廠的花費(fèi),顧客為了滿足自己的需求,需要找到容量足夠的而且花費(fèi)比較少的工廠;最后是工廠的容量,不能無限滿足所有顧客的需求。這個(gè)問題的約束條件非常多,如果用傳統(tǒng)的動態(tài)規(guī)劃的思路來做,狀態(tài)空間會非常大而且不好設(shè)計(jì)動態(tài)規(guī)劃轉(zhuǎn)移方程。因此,在這道題中我沒有用到動態(tài)規(guī)劃的思路。
貪心算法
如果動歸很難設(shè)計(jì)的話,第一時(shí)間想到的就是貪心的算法。在滿足約束的情況下找到最小解,貪心的思路就是:在滿足每一個(gè)需求的時(shí)候都找一個(gè)最小的花費(fèi)。設(shè)計(jì)起來也比較簡單:假設(shè)所有工廠都是開放的,對于每一個(gè)顧客的需求,我們都找一個(gè)最小的,而且容量還足夠的工廠。
FOR each customer:
loop: find the factory with the smallest cost
if the capacity of the factory smaller than the demand of the customer
goto loop
else
total cost += the cost of the customer going to the factory
FOR each factory:
if nobody going to the factory
total cost -= the opening cost
以上就是貪心算法的大概流程,我們需要遍歷一次所有的顧客需求,然后找到最小的花費(fèi),這里可以用優(yōu)先隊(duì)列(heap)或者用排序算法從頭開始找最好的工廠。由于題目保證了每個(gè)樣例都有解,因此不需要特意考慮如果對于一個(gè)需求而言沒有任何一個(gè)工廠能夠有足夠的容量來滿足的情況。
盡管如此,貪心算法找到的solution并不是沒有提升空間。這個(gè)算法只能解決customer到工廠最小花費(fèi)的問題,但是沒有考慮到開設(shè)工廠需要的花費(fèi),因此,從根本上來說,貪心算法達(dá)到的解不會是全局最優(yōu)解。另外,由于現(xiàn)在是按照順序?qū)︻櫩瓦M(jìn)行遍歷,前面的顧客可能會占據(jù)了后面的顧客的工廠容量,因此,達(dá)到的解也不一定是最優(yōu)的。
為了讓貪心算法盡可能逼近最優(yōu)解,我們可以采用隨機(jī)調(diào)換顧客順序的方式,將得到的結(jié)果進(jìn)行對比,得到相對較好的解。
模擬退火算法
前面提到了,貪心算法得到的解只是一個(gè)局部的最優(yōu)解,并不能達(dá)到全局最優(yōu)解。而這時(shí),用模擬退火算法就可以有一定幾率跳出局部最優(yōu)解,到達(dá)全局最優(yōu)解。
一開始,先隨機(jī)一個(gè)解,這個(gè)解需要滿足:
- 所有顧客都被滿足
- 工廠還有剩余容量
然后,通過模擬退火算法:
T := INITIAL_TEMPERATURE
WHILE T > END_TEMPERATURE
for i from 1 to 1500:
generate new solution
if the cost of the new solution is smaller than the cost of the origin
accept the new solution
else
delta := new_cost - self.cost
probility := exp(-delta / T)
if probility > random
accept the new solution
T := T * 0.98
以上是模擬退火算法的大體流程。生成新解的方式(鄰域搜索方式)是:(1)隨機(jī)選取兩個(gè)顧客交換它們的工廠(2)隨機(jī)改變一個(gè)顧客的工廠。當(dāng)然,生成的新解同樣也需要滿足原來的約束條件。
從結(jié)果可以看出,退火算法可以跳出局部最優(yōu)解,但是,最后收斂的解也不一定是全局最優(yōu)解,但值得肯定的是,退火算法得到的結(jié)果是比貪心的結(jié)果要優(yōu)秀的。但不足的地方是,模擬退火算法的收斂需要很長的時(shí)間,而貪心算法則很快就能找到一個(gè)解。
結(jié)果分析
| number | greed cost | sa cost |
|---|---|---|
| 1 | 9440.0 | 8863.0 |
| 2 | 8126.0 | 7942.0 |
| 3 | 10126.0 | 9382.0 |
| 4 | 12126.0 | 10714.0 |
| 5 | 9375.0 | 8838.0 |
| 6 | 8061.0 | 7781.0 |
| 7 | 10061.0 | 9784.0 |
| 8 | 12061.0 | 11088.0 |
| 9 | 9040.0 | 8477.0 |
| 10 | 7726.0 | 7648.0 |
| 11 | 9726.0 | 8932.0 |
| 12 | 11726.0 | 10132.0 |
| 13 | 12032.0 | 8418.0 |
| 14 | 9180.0 | 7396.0 |
| 15 | 13180.0 | 9906.0 |
| 16 | 17180.0 | 11292.0 |
| 17 | 12032.0 | 8464.0 |
| 18 | 9180.0 | 7125.0 |
| 19 | 13180.0 | 8914.0 |
| 20 | 17180.0 | 11136.0 |
| 21 | 12032.0 | 8144.0 |
| 22 | 9180.0 | 7266.0 |
| 23 | 13180.0 | 8806.0 |
| 24 | 17180.0 | 11665.0 |
| 25 | 19197.0 | 12612.0 |
| 26 | 16131.0 | 11325.0 |
| 27 | 21531.0 | 13506.0 |
| 28 | 26931.0 | 15022.0 |
| 29 | 19305.0 | 13400.0 |
| 30 | 16239.0 | 11411.0 |
| 31 | 21639.0 | 14181.0 |
| 32 | 27039.0 | 16508.0 |
| 33 | 19055.0 | 12796.0 |
| 34 | 15989.0 | 11004.0 |
| 35 | 21389.0 | 13485.0 |
| 36 | 26789.0 | 15685.0 |
| 37 | 19055.0 | 12200.0 |
| 38 | 15989.0 | 11282.0 |
| 39 | 21389.0 | 12984.0 |
| 40 | 26789.0 | 14984.0 |
| 41 | 7226.0 | 6908.0 |
| 42 | 9957.0 | 6544.0 |
| 43 | 12448.0 | 6510.0 |
| 44 | 7585.0 | 7128.0 |
| 45 | 9848.0 | 6815.0 |
| 46 | 12639.0 | 6372.0 |
| 48 | 9044.0 | 6333.0 |
| 49 | 12420.0 | 5394.0 |
| 50 | 10062.0 | 9256.0 |
| 51 | 11351.0 | 7969.0 |
| 52 | 10364.0 | 9452.0 |
| 53 | 12470.0 | 9030.0 |
| 54 | 10351.0 | 9052.0 |
| 55 | 11970.0 | 8227.0 |
| 56 | 23882.0 | 22975.0 |
| 57 | 32882.0 | 29482.0 |
| 58 | 53882.0 | 44011.0 |
| 59 | 39121.0 | 33420.0 |
| 60 | 23882.0 | 22669.0 |
| 61 | 32882.0 | 29167.0 |
| 62 | 53882.0 | 42657.0 |
| 63 | 39121.0 | 32332.0 |
| 64 | 23882.0 | 22886.0 |
| 65 | 32882.0 | 29203.0 |
| 66 | 53882.0 | 44138.0 |
| 68 | 23882.0 | 22561.0 |
| 69 | 32882.0 | 29567.0 |
| 70 | 53882.0 | 43869.0 |
| 71 | 39121.0 | 33154.0 |
從這里我們可以很清晰的看出,退火算法得到的結(jié)果比貪心算法是有很大的提升的。