问题 CFLP

Capacitated-Facility-Location-Problem
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

Note:

  1. The objective is to minimize the sum of the opening cost and the
    assignment cost.
  2. The total demand assigned to a facility must not exceed its
    capacity.
  • Input format

Capacitated-Facility-Location-Problem

  • Result_requirement

Capacitated-Facility-Location-Problem


分析

这道题是有容量的设施选址问题,主要的难点在于有容量限制与工产费用限制,其中每个工厂开设需要一定的费用,解决工厂开设的费用与用户需求、客户选择服务工厂以及工厂容量问题四者之间的平衡问题成为了解题的关键之处。
通过分析,最后采用了基于贪心的模拟退火算法、局部搜索法、贪心算法。


基于贪心的模拟退火算法(以及局部搜索法)

  • 算法框架
    Capacitated-Facility-Location-Problem
  • 在实现模拟退火算法的过程中,最重要的是如何从原状态产生新解,我在实现的过程中采用了5种产生新状态的方法,对5种新状态采用局部贪心,选择最好的方法,再进行模拟退火的判断最后得到结果
    1. 随机交换两个顾客的工厂
    2. 随机将一个顾客放入一个随机工厂中
    3. 交换两个顾客中间所有顾客的工厂(例如交换1-4 14换 23换)
    4. 按顺序交换两个顾客中间的顾客(例如交换1-3 12换 23换 31换)
    5. 随机将两个顾客放入两个随机工厂中
  • 在模拟退火的过程中如果不接受差解则转化为局部搜索算法(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

局部搜索最优解
局部搜索所有测试解
模拟退火最优解
模拟退火所有测试解
贪心算法结果


结论

  1. 通过对结果的分析,模拟退火算法的求解是最好的,有20组数据求出了最优解,其余解也都不超过最优解的10%。求解时间较长,这是受初始解的影响,若用贪心算法的结果作为初始解,则可以显著的节省时间,上述的方法是使用随机的初始解开始计算的,导致时间较长。
  2. 局部搜索的结果会比模拟退火的结果差,并随着时间的增加不会有额外的变化,时间问题与模拟退火基本相同。
  3. 贪心算法的求解则较差,受数据的影响很大,但求解时间短。

参考资料

Multi-Exchange Heuristics for some Capacitated Facility Location Problems


Github

项目源码

相关文章:

  • 2021-06-28
  • 2022-02-11
  • 2022-02-27
  • 2021-06-10
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-07-13
  • 2021-10-16
  • 2021-03-31
  • 2022-12-23
  • 2021-04-07
  • 2021-04-15
  • 2021-09-27
相关资源
相似解决方案