Capacitated-Facility-Location-Problem

问题 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

Input format

  • Result_requirement

Result requirement


分析

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


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

  • 算法框架
    在这里插入图片描述
  • 在实现模拟退火算法的过程中,最重要的是如何从原状态产生新解,我在实现的过程中采用了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)
p1884893240.001922410.652884836.759
p2791380100.002797411.497791340.093
p39314100100.001977411.755931436.769
p410714120100.0011129711.5291071437.409
p5883891690.003916912.872883835.809
p6777778550.003785510.976777735.239
p7948898550.002974312.278948835.869
p811088118550.0011149911.441108836.749
p9846290400.017874212.377846234.139
p10761777260.037764812.111761733.69
p11893297260.016930511.618893234.169
p1210132117260.0091042712.0441013236.011
p138252120320.014944512.396826035.049
p14713791800.019763111.362713737.002
p158808131800.011030211.945889235.678
p1610408171800.0161233811.3121046236.065
p178227120320.003869710.975824034.595
p18712591800.005805711.003712534.472
p198886131800.0041022111.633888734.897
p2010486171800.0121183011.3211048735.271
p218068120320.007931911.084806834.931
p22709291800.003770410.812709234.529
p238746171800.0031009410.97874636.122
p2410273120100.0011179810.9841034635.662
p2511630190890.0241457754.70511900104.904
p2610771160230.0221303550.49410989106.632
p2712322214230.0271549649.58812617107.509
p2813722268230.0241846449.54413972114.124
p2912371190590.0191467249.20812670105.275
p3011331159930.0191276448.51711461102.801
p3113331213930.021560958.7341360897.409
p3215331267930.0211847556.0311580897.273
p3311629190550.0211416158.5341184999.978
p3410632159890.021216949.8571082097.826
p3512232213890.0211545353.21912568100.122
p3613832267890.0271774955.10614368100.517
p3711258190550.0211316552.0811158099.754
p3811088159890.0191216657.5421086598.718
p3911824213890.0251504950.19812244100.625
p4013024267890.0191724551.12113351105.361
p41658971130.003691823.344670546.885
p42566399570.006750719.172568039.45
p435214124480.006977411.755553335.678
p44702874000.003708922.53702843.165
p45625198480.006750018.937628537.844
p465651126390.01731916.428576632.934
p47622864140.003630520.853622840.834
p48559690440.008697315.647577136.744
p495302124200.011678512.377569532.01
p50874198540.005926327.571889952.731
p517414113330.007926328.413752155.39
p529178103320.004931628.862918053.405
p538531124700.008974228.432853154.057
p54877798430.004940625.08883849.755
p557654119210.007919025.562778651.39
p5621103238820.042313576.59222300143.435
p5726039328820.0393047175.3628010145.595
p5837239538820.044815673.4640696147.143
p5927282391210.0393623974.10229910144.108
p6020534238820.0392280373.00921721144.144
p6124454328820.0392935474.49225850147.204
p6232643538820.044738173.94237156149.416
p6325105391210.0393466974.34726802149.714
p6420530238820.0392272376.69621658143.266
p6524445328820.0412835375.10826811146.476
p6631415538820.044462686.16834676152.225
p6724848396710.06334051102.24627356148.53
p6820538238820.042281495.81321860144.264
p6924532328820.0392953295.86126505146.939
p7032321538820.044710893.59136939152.249
p7125540391210.03934919100.3952781727817

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


结论

  1. 通过对结果的分析,模拟退火算法的求解是最好的,有20组数据求出了最优解,其余解也都不超过最优解的10%。但缺点是求解时间较长。
  2. 局部搜索的结果会比模拟退火的结果差,并随着时间的增加不会有额外的变化,时间问题与模拟退火基本相同。
  3. 贪心算法的求解则较差,受数据的影响很大,但求解时间短。

参考资料

Multi-Exchange Heuristics for some Capacitated Facility Location Problems


Github

项目源码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妙BOOK言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值