问题 CFLP
Capacitated-Facility-Location-Problem
Suppose there are n facilities and m customers. We wish to choose:
- which of the n facilities to open
- the assignment of customers to facilities
Note:
- 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.
- Input format
- Result_requirement
分析
这道题是有容量的设施选址问题,主要的难点在于有容量限制与工产费用限制,其中每个工厂开设需要一定的费用,解决工厂开设的费用与用户需求、客户选择服务工厂以及工厂容量问题四者之间的平衡问题成为了解题的关键之处。
通过分析,最后采用了基于贪心的模拟退火算法、局部搜索法、贪心算法。
基于贪心的模拟退火算法(以及局部搜索法)
- 算法框架
- 在实现模拟退火算法的过程中,最重要的是如何从原状态产生新解,我在实现的过程中采用了5种产生新状态的方法,对5种新状态采用局部贪心,选择最好的方法,再进行模拟退火的判断最后得到结果
- 随机交换两个顾客的工厂
- 随机将一个顾客放入一个随机工厂中
- 交换两个顾客中间所有顾客的工厂(例如交换1-4 14换 23换)
- 按顺序交换两个顾客中间的顾客(例如交换1-3 12换 23换 31换)
- 随机将两个顾客放入两个随机工厂中
- 在模拟退火的过程中如果不接受差解则转化为局部搜索算法(LS),也就是爬山法
贪心算法
- 从顾客 x 开始遍历所有顾客,选择当前顾客允许的最优解,最终得到从顾客 x 开始的最优解
- 对所有顾客分别通过贪心算法得到该顾客的最优解,从所有解中取最优得到贪心算法的结果
代码实现
程序运行方式见 github
基于贪心的模拟退火算法(以及局部搜索法)
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <sys/time.h>
#include <cmath>
#include <string.h>
#include <stdlib.h>
using namespace std;
int Facility = 0;
int Customer = 0;
vector<vector<int> >FacilityInfo;
vector<vector<int> >CustomerInfo;
// Segmentation of string 's' by the separator 'separator' and store in 'v'
void SplitString(const string& s, vector<string>& v, const string& separator) {
string::size_type pos1, pos2;
pos2 = s.find(separator);
pos1 = 0;
while(string::npos != pos2)
{
v.push_back(s.substr(pos1, pos2-pos1));
pos1 = pos2 + separator.size();
pos2 = s.find(separator, pos1);
}
if(pos1 != s.length())
v.push_back(s.substr(pos1));
}
// string to int
int String2Int(string str) {
stringstream ss;
ss << str;
int res;
ss >> res;
return res;
}
// read File
void readFile(string path) {
ifstream file(path.c_str());
vector<string> split;
string line;
if (!file.is_open()) {
cout << "open file filed" << endl;
} else {
getline(file, line);
SplitString(line, split, " ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
Facility = String2Int(split[0]);
Customer = String2Int(split[split.size()-1]);
}
int FacilityCapacityNum = 0;
int CustomerDemandNum = 0;
int FacilityNum = 0;
int CustomerAssignmentNum = 0;
while(getline(file,line)) {
vector<string> split;
if(FacilityCapacityNum < Facility) {
FacilityCapacityNum ++;
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
std::vector<int> v;
v.push_back(String2Int(split[0]));
v.push_back(String2Int(split[split.size()-1]));
FacilityInfo.push_back(v);
} else if(CustomerDemandNum < Customer) {
// CustomerDemandNum ++;
SplitString(line, split,".");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
if (split.size() == 1) {
split.clear();
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
}
for(int i = 0; i < split.size(); i++) {
std::vector<int> v;
v.push_back(String2Int(split[i]));
CustomerInfo.push_back(v);
}
CustomerDemandNum += split.size();
} else if(FacilityNum < Facility) {
SplitString(line, split,".");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
if (split.size() == 1) {
split.clear();
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
}
for(int i = 0; i < split.size(); i++) {
CustomerInfo[CustomerAssignmentNum].push_back(String2Int(split[i]));
CustomerAssignmentNum ++;
}
if(CustomerAssignmentNum == Customer) {
CustomerAssignmentNum = 0;
FacilityNum ++;
}
}
}
}
// Simulated annealing
vector<int> FacilityRes;
vector<int> CustomerRes;
int best = 0;
vector<int> FacilityBest;
vector<int> CustomerBest;
vector<int> FacilityBefore;
vector<int> CustomerBefore;
// Calculate the consumption of current results
int calulate() {
int consume = 0;
for(int i = 0; i < Facility; i++) {
if(FacilityRes[i] == 1) consume += FacilityInfo[i][1];
}
for(int i = 0; i < Customer; i++) {
consume += CustomerInfo[i][CustomerRes[i]+1];
}
return consume;
}
// Initialize a solution
void init() {
int consume = 0;
int FacilityNum = 0;
for(int j = 0; j < Customer; j++) {
if(consume+CustomerInfo[j][0] < FacilityInfo[FacilityNum][0]) {
CustomerRes.push_back(FacilityNum);
consume += CustomerInfo[j][0];
} else {
consume = 0;
FacilityNum ++;
j--;
}
}
for(int i = 0; i < Facility; i++) {
FacilityRes.push_back(1);
}
best = calulate();
FacilityBest.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBest.assign(CustomerRes.begin(), CustomerRes.end());
}
// Determine whether two customers can exchange
bool valid(int r1, int r2) {
int sum1 = 0;
int sum2 = 0;
for(int i = 0; i < Customer; i++) {
if(i != r1 && CustomerRes[i] == CustomerRes[r1]) {
sum1 += CustomerInfo[i][0];
} else if(i != r2 && CustomerRes[i] == CustomerRes[r2]) {
sum2 += CustomerInfo[i][0];
}
}
if (sum1+CustomerInfo[r2][0] < FacilityInfo[CustomerRes[r1]][0] &&
sum2+CustomerInfo[r1][0] < FacilityInfo[CustomerRes[r2]][0]) {
return true;
}
return false;
}
bool valid2() {
int FacilitySum[Facility];
memset(FacilitySum, 0, Facility*sizeof(FacilitySum[0]));
for(int i = 0; i < Customer; i++) {
FacilitySum[CustomerRes[i]] += CustomerInfo[i][0];
}
bool flag = true;
for(int i = 0; i < Facility; i++) {
if(FacilitySum[i] > 0 && FacilitySum[i] < FacilityInfo[i][0])
FacilityRes[i] = 1;
if(FacilitySum[i] > FacilityInfo[i][0])
flag = false;
}
return flag;
}
// various exchange methods
void method1(int r1, int r2) {
if (valid(r1, r2)) {
int tem = CustomerRes[r1];
CustomerRes[r1] = CustomerRes[r2];
CustomerRes[r2] = tem;
}
}
void method2(int r1, int r2) {
int OriginalFactory = CustomerRes[r1];
int sum = 0;
for (int i = 0; i < Customer; i++) {
if (CustomerRes[i] == r2) {
sum += CustomerInfo[i][0];
}
}
if (sum+CustomerInfo[r1][0] < FacilityInfo[r2][0]) {
CustomerRes[r1] = r2;
FacilityRes[r2] = 1;
for(int i = 0; i < Customer; i++) {
if(CustomerRes[i] == OriginalFactory)
OriginalFactory = -1;
}
if(OriginalFactory != -1)
FacilityRes[OriginalFactory] = 0;
}
}
void method3(int r1, int r2) {
if (r1 > r2) {
int tem = r1;
r1 = r2;
r2 = tem;
}
while(r1 < r2) {
if (valid(r1, r2)) {
int tem = CustomerRes[r1];
CustomerRes[r1] = CustomerRes[r2];
CustomerRes[r2] = tem;
}
r1 ++;
r2 --;
}
}
void method4(int r1, int r2) {
if (r1 > r2) {
int tem = r1;
r1 = r2;
r2 = tem;
}
if (r2 == 0)
r2 ++;
FacilityBefore.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBefore.assign(CustomerRes.begin(), CustomerRes.end());
int tem = CustomerRes[r1];
for(int i = r1; i < r2-1; i++) {
CustomerRes[r1] = CustomerRes[r1+1];
}
CustomerRes[r2-1] = tem;
if(!valid2()) {
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
}
}
void method5(int r1, int r2, int r3, int r4) {
FacilityBefore.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBefore.assign(CustomerRes.begin(), CustomerRes.end());
CustomerRes[r3] = r1;
CustomerRes[r4] = r2;
if(!valid2()) {
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
}
}
// create new solution
// local greed, compare various exchange methods, choose the best method
void newSolutions() {
FacilityBefore.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBefore.assign(CustomerRes.begin(), CustomerRes.end());
int r1 = rand()%Customer;
int r2 = rand()%Customer;
method1(r1, r2);
int res1 = calulate();
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
int r3 = rand()%Customer;
int r4 = rand()%Facility;
method2(r3, r4);
int res2 = calulate();
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
int r5 = rand()%Customer;
int r6 = rand()%Customer;
method3(r5, r6);
int res3 = calulate();
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
int r7 = rand()%Customer;
int r8 = rand()%Customer;
method4(r7, r8);
int res4 = calulate();
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
int r9 = rand()%Facility;
int r10 = rand()%Facility;
int r11 = rand()%Customer;
int r12 = rand()%Customer;
while(r11 == r12) {
r12 = rand()%Customer;
}
method5(r9, r10, r11, r12);
int res5 = calulate();
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
if(res1 <= res2 && res1 <= res3 && res1 <= res4 && res1 <= res5) {
method1(r1, r2);
} else if(res2 <= res1 && res2 <= res3 && res2 <= res4 && res2 <= res5) {
method2(r3, r4);
} else if(res3 <= res1 && res3 <= res2 && res3 <= res4 && res3 <= res5) {
method3(r5, r6);
} else if(res4 <= res1 && res4 <= res2 && res4 <= res3 && res4 <= res5) {
method4(r7, r8);
} else {
method5(r9, r10, r11, r12);
}
}
void simulateAnneal() {
double T = 100;
double T_end = 10e-5;
int innerLoop = 1000;
double cooling_rate = 0.99;
double T_cout = T/10;
init();
while(T > T_end) {
innerLoop *= 1.0001;
int d ;
for(int i = 0; i < innerLoop; i++) {
int before = calulate();
FacilityBefore.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBefore.assign(CustomerRes.begin(), CustomerRes.end());
newSolutions();
d = calulate() - before;
double ran = rand()%1000/1000.0;
if (d < 0 || exp(-d / T / 10) > ran) {
;
} else {
FacilityRes.assign(FacilityBefore.begin(),FacilityBefore.end());
CustomerRes.assign(CustomerBefore.begin(),CustomerBefore.end());
}
if (best > calulate()) {
best = calulate();
FacilityBest.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBest.assign(CustomerRes.begin(), CustomerRes.end());
}
}
T *= cooling_rate;
if (T < T_cout) {
cout << T << " " << calulate() << endl;
T_cout /= 10;
}
}
}
int main(int argc, char *argv[]) {
srand((unsigned int)(time(NULL)));
string p(argv[1]);
string File = "p" + p;
clock_t start, stop;
start = clock();
readFile("Instances\\\\" + File);
simulateAnneal();
stop = clock();
ofstream in;
in.open("res.txt", ios_base::app);
in << "Use Time: " << (double)(stop-start)/CLOCKS_PER_SEC << " s" << endl;
in << "result: " << endl;
in << best << endl;
for(int i = 0; i < Facility; i++) {
in << FacilityBest[i] << " ";
}
in << endl;
for(int i = 0; i < Customer; i++) {
in << CustomerBest[i] << " ";
}
in << endl;
in << endl;
in.close();
cout << best << endl;
return 0;
}
贪心算法
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <sys/time.h>
#include <cmath>
#include <string.h>
#include <stdlib.h>
using namespace std;
int Facility = 0;
int Customer = 0;
vector<vector<int> >FacilityInfo;
vector<vector<int> >CustomerInfo;
// Segmentation of string 's' by the separator 'separator' and store in 'v'
void SplitString(const string& s, vector<string>& v, const string& separator) {
string::size_type pos1, pos2;
pos2 = s.find(separator);
pos1 = 0;
while(string::npos != pos2)
{
v.push_back(s.substr(pos1, pos2-pos1));
pos1 = pos2 + separator.size();
pos2 = s.find(separator, pos1);
}
if(pos1 != s.length())
v.push_back(s.substr(pos1));
}
// string to int
int String2Int(string str) {
stringstream ss;
ss << str;
int res;
ss >> res;
return res;
}
// read File
void readFile(string path) {
ifstream file(path.c_str());
vector<string> split;
string line;
if (!file.is_open()) {
cout << "open file filed" << endl;
} else {
getline(file, line);
SplitString(line, split, " ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
Facility = String2Int(split[0]);
Customer = String2Int(split[split.size()-1]);
}
int FacilityCapacityNum = 0;
int CustomerDemandNum = 0;
int FacilityNum = 0;
int CustomerAssignmentNum = 0;
while(getline(file,line)) {
vector<string> split;
if(FacilityCapacityNum < Facility) {
FacilityCapacityNum ++;
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
std::vector<int> v;
v.push_back(String2Int(split[0]));
v.push_back(String2Int(split[split.size()-1]));
FacilityInfo.push_back(v);
} else if(CustomerDemandNum < Customer) {
// CustomerDemandNum ++;
SplitString(line, split,".");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
if (split.size() == 1) {
split.clear();
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
}
for(int i = 0; i < split.size(); i++) {
std::vector<int> v;
v.push_back(String2Int(split[i]));
CustomerInfo.push_back(v);
}
CustomerDemandNum += split.size();
} else if(FacilityNum < Facility) {
SplitString(line, split,".");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
if (split.size() == 1) {
split.clear();
SplitString(line, split," ");
for(vector<string>::iterator it = split.begin(); it != split.end(); ) {
if(*it == "") it = split.erase(it);
else it ++;
}
}
for(int i = 0; i < split.size(); i++) {
CustomerInfo[CustomerAssignmentNum].push_back(String2Int(split[i]));
CustomerAssignmentNum ++;
}
if(CustomerAssignmentNum == Customer) {
CustomerAssignmentNum = 0;
FacilityNum ++;
}
}
}
}
vector<int> FacilityRes;
vector<int> CustomerRes;
vector<int> FacilitySum;
int best = 1000000;
vector<int> FacilityBest;
vector<int> CustomerBest;
// Calculate the consumption of current results
int calulate() {
int consume = 0;
for(int i = 0; i < Facility; i++) {
if(FacilityRes[i] == 1) consume += FacilityInfo[i][1];
}
for(int i = 0; i < Customer; i++) {
consume += CustomerInfo[i][CustomerRes[i]+1];
}
return consume;
}
void Greedy() {
for(int ii = 0; ii < Facility; ii++) {
FacilityRes.push_back(0);
FacilitySum.push_back(0);
}
for(int ii = 0; ii < Customer; ii++) {
CustomerRes.push_back(-1);
}
for(int i = 0; i < Customer; i++) {
for(int ii = 0; ii < Facility; ii++) {
FacilityRes[ii] = 0;
FacilitySum[ii] = 0;
}
for(int ii = 0; ii < Customer; ii++) {
CustomerRes[ii] = -1;
}
for(int j = i; j < Customer; j++) {
int mincost = 100000;
int minFacility = -1;
for(int k = 0; k < Facility; k++) {
if(FacilitySum[k]+CustomerInfo[j][0] < FacilityInfo[k][0] && mincost > CustomerInfo[j][k+1]) {
mincost = CustomerInfo[j][k+1];
minFacility = k;
}
}
FacilityRes[minFacility] = 1;
CustomerRes[j] = minFacility;
FacilitySum[minFacility] += CustomerInfo[j][0];
}
for(int j = 0; j < i; j++) {
int mincost = 100000;
int minFacility = -1;
for(int k = 0; k < Facility; k++) {
if(FacilitySum[k]+CustomerInfo[j][0] < FacilityInfo[k][0] && mincost > CustomerInfo[j][k+1]) {
mincost = CustomerInfo[j][k+1];
minFacility = k;
}
}
FacilityRes[minFacility] = 1;
CustomerRes[j] = minFacility;
FacilitySum[minFacility] += CustomerInfo[j][0];
}
if(best > calulate()) {
best = calulate();
FacilityBest.assign(FacilityRes.begin(), FacilityRes.end());
CustomerBest.assign(CustomerRes.begin(), CustomerRes.end());
}
}
}
int main(int argc, char *argv[]) {
string p(argv[1]);
string File = "p" + p;
clock_t start, stop;
start = clock();
readFile("Instances\\\\" + File);
Greedy();
stop = clock();
ofstream in;
in.open("res.txt", ios_base::app);
in << "Use Time: " << (double)(stop-start)/CLOCKS_PER_SEC << " s" << endl;
in << "result: " << endl;
in << best << endl;
for(int i = 0; i < Facility; i++) {
in << FacilityBest[i] << " ";
}
in << endl;
for(int i = 0; i < Customer; i++) {
in << CustomerBest[i] << " ";
}
in << endl;
in << endl;
in.close();
cout << best << endl;
return 0;
}
结果
文件 | 查找资料的最优解 | 贪心算法结果 | 时间(s) | LS局部搜索结果 | 时间(s) | SA模拟退火结果 | 时间(s) |
---|---|---|---|---|---|---|---|
p1 | 8848 | 9324 | 0.001 | 9224 | 10.652 | 8848 | 36.759 |
p2 | 7913 | 8010 | 0.002 | 7974 | 11.497 | 7913 | 40.093 |
p3 | 9314 | 10010 | 0.001 | 9774 | 11.755 | 9314 | 36.769 |
p4 | 10714 | 12010 | 0.001 | 11297 | 11.529 | 10714 | 37.409 |
p5 | 8838 | 9169 | 0.003 | 9169 | 12.872 | 8838 | 35.809 |
p6 | 7777 | 7855 | 0.003 | 7855 | 10.976 | 7777 | 35.239 |
p7 | 9488 | 9855 | 0.002 | 9743 | 12.278 | 9488 | 35.869 |
p8 | 11088 | 11855 | 0.001 | 11499 | 11.44 | 11088 | 36.749 |
p9 | 8462 | 9040 | 0.017 | 8742 | 12.377 | 8462 | 34.139 |
p10 | 7617 | 7726 | 0.037 | 7648 | 12.111 | 7617 | 33.69 |
p11 | 8932 | 9726 | 0.016 | 9305 | 11.618 | 8932 | 34.169 |
p12 | 10132 | 11726 | 0.009 | 10427 | 12.044 | 10132 | 36.011 |
p13 | 8252 | 12032 | 0.014 | 9445 | 12.396 | 8260 | 35.049 |
p14 | 7137 | 9180 | 0.019 | 7631 | 11.362 | 7137 | 37.002 |
p15 | 8808 | 13180 | 0.01 | 10302 | 11.945 | 8892 | 35.678 |
p16 | 10408 | 17180 | 0.016 | 12338 | 11.312 | 10462 | 36.065 |
p17 | 8227 | 12032 | 0.003 | 8697 | 10.975 | 8240 | 34.595 |
p18 | 7125 | 9180 | 0.005 | 8057 | 11.003 | 7125 | 34.472 |
p19 | 8886 | 13180 | 0.004 | 10221 | 11.633 | 8887 | 34.897 |
p20 | 10486 | 17180 | 0.012 | 11830 | 11.321 | 10487 | 35.271 |
p21 | 8068 | 12032 | 0.007 | 9319 | 11.084 | 8068 | 34.931 |
p22 | 7092 | 9180 | 0.003 | 7704 | 10.812 | 7092 | 34.529 |
p23 | 8746 | 17180 | 0.003 | 10094 | 10.97 | 8746 | 36.122 |
p24 | 10273 | 12010 | 0.001 | 11798 | 10.984 | 10346 | 35.662 |
p25 | 11630 | 19089 | 0.024 | 14577 | 54.705 | 11900 | 104.904 |
p26 | 10771 | 16023 | 0.022 | 13035 | 50.494 | 10989 | 106.632 |
p27 | 12322 | 21423 | 0.027 | 15496 | 49.588 | 12617 | 107.509 |
p28 | 13722 | 26823 | 0.024 | 18464 | 49.544 | 13972 | 114.124 |
p29 | 12371 | 19059 | 0.019 | 14672 | 49.208 | 12670 | 105.275 |
p30 | 11331 | 15993 | 0.019 | 12764 | 48.517 | 11461 | 102.801 |
p31 | 13331 | 21393 | 0.02 | 15609 | 58.734 | 13608 | 97.409 |
p32 | 15331 | 26793 | 0.021 | 18475 | 56.031 | 15808 | 97.273 |
p33 | 11629 | 19055 | 0.021 | 14161 | 58.534 | 11849 | 99.978 |
p34 | 10632 | 15989 | 0.02 | 12169 | 49.857 | 10820 | 97.826 |
p35 | 12232 | 21389 | 0.021 | 15453 | 53.219 | 12568 | 100.122 |
p36 | 13832 | 26789 | 0.027 | 17749 | 55.106 | 14368 | 100.517 |
p37 | 11258 | 19055 | 0.021 | 13165 | 52.081 | 11580 | 99.754 |
p38 | 11088 | 15989 | 0.019 | 12166 | 57.542 | 10865 | 98.718 |
p39 | 11824 | 21389 | 0.025 | 15049 | 50.198 | 12244 | 100.625 |
p40 | 13024 | 26789 | 0.019 | 17245 | 51.121 | 13351 | 105.361 |
p41 | 6589 | 7113 | 0.003 | 6918 | 23.344 | 6705 | 46.885 |
p42 | 5663 | 9957 | 0.006 | 7507 | 19.172 | 5680 | 39.45 |
p43 | 5214 | 12448 | 0.006 | 9774 | 11.755 | 5533 | 35.678 |
p44 | 7028 | 7400 | 0.003 | 7089 | 22.53 | 7028 | 43.165 |
p45 | 6251 | 9848 | 0.006 | 7500 | 18.937 | 6285 | 37.844 |
p46 | 5651 | 12639 | 0.01 | 7319 | 16.428 | 5766 | 32.934 |
p47 | 6228 | 6414 | 0.003 | 6305 | 20.853 | 6228 | 40.834 |
p48 | 5596 | 9044 | 0.008 | 6973 | 15.647 | 5771 | 36.744 |
p49 | 5302 | 12420 | 0.011 | 6785 | 12.377 | 5695 | 32.01 |
p50 | 8741 | 9854 | 0.005 | 9263 | 27.571 | 8899 | 52.731 |
p51 | 7414 | 11333 | 0.007 | 9263 | 28.413 | 7521 | 55.39 |
p52 | 9178 | 10332 | 0.004 | 9316 | 28.862 | 9180 | 53.405 |
p53 | 8531 | 12470 | 0.008 | 9742 | 28.432 | 8531 | 54.057 |
p54 | 8777 | 9843 | 0.004 | 9406 | 25.08 | 8838 | 49.755 |
p55 | 7654 | 11921 | 0.007 | 9190 | 25.562 | 7786 | 51.39 |
p56 | 21103 | 23882 | 0.04 | 23135 | 76.592 | 22300 | 143.435 |
p57 | 26039 | 32882 | 0.039 | 30471 | 75.36 | 28010 | 145.595 |
p58 | 37239 | 53882 | 0.04 | 48156 | 73.46 | 40696 | 147.143 |
p59 | 27282 | 39121 | 0.039 | 36239 | 74.102 | 29910 | 144.108 |
p60 | 20534 | 23882 | 0.039 | 22803 | 73.009 | 21721 | 144.144 |
p61 | 24454 | 32882 | 0.039 | 29354 | 74.492 | 25850 | 147.204 |
p62 | 32643 | 53882 | 0.04 | 47381 | 73.942 | 37156 | 149.416 |
p63 | 25105 | 39121 | 0.039 | 34669 | 74.347 | 26802 | 149.714 |
p64 | 20530 | 23882 | 0.039 | 22723 | 76.696 | 21658 | 143.266 |
p65 | 24445 | 32882 | 0.041 | 28353 | 75.108 | 26811 | 146.476 |
p66 | 31415 | 53882 | 0.04 | 44626 | 86.168 | 34676 | 152.225 |
p67 | 24848 | 39671 | 0.063 | 34051 | 102.246 | 27356 | 148.53 |
p68 | 20538 | 23882 | 0.04 | 22814 | 95.813 | 21860 | 144.264 |
p69 | 24532 | 32882 | 0.039 | 29532 | 95.861 | 26505 | 146.939 |
p70 | 32321 | 53882 | 0.04 | 47108 | 93.591 | 36939 | 152.249 |
p71 | 25540 | 39121 | 0.039 | 34919 | 100.395 | 27817 | 27817 |
局部搜索最优解
局部搜索所有测试解
模拟退火最优解
模拟退火所有测试解
贪心算法结果
结论
- 通过对结果的分析,模拟退火算法的求解是最好的,有20组数据求出了最优解,其余解也都不超过最优解的10%。但缺点是求解时间较长。
- 局部搜索的结果会比模拟退火的结果差,并随着时间的增加不会有额外的变化,时间问题与模拟退火基本相同。
- 贪心算法的求解则较差,受数据的影响很大,但求解时间短。
参考资料
Multi-Exchange Heuristics for some Capacitated Facility Location Problems