vrptw

  前段时间做了个vrptw(有时间窗车辆路径问题)的作业,用的算法是Solomon (1987)里1.3的插入启发算法。然后调用百度地图的接口在地图上显示路径。思路是用vrptw程序计算出路径输出保存到json文件中,然后上传json文件,解析,用百度地图接口将路径绘制出来。代码如下,仅供参考。

/*
LANG: C++
PROG: VRPTW
*/
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
#include <time.h>
using namespace std;

#define NUM 101											//custom数目(含depot)
#define CRITERIA_DIST 0									//初如化标准距离
#define CRITERIA_TIME 1									//初始化时间距离

typedef struct
{
	double x, y, demand, rtime, dtime, stime;
	double btime, wtime, c2;
	int pos;
	bool flag;
} cust;

const int mu[4] = { 1, 1, 1, 1 };						//c1, c2函数的参数
const int lambda[4] = { 1, 2, 1, 2 };
const int alpha1[4] = { 1, 1, 0, 0 };
const int alpha2[4] = { 0, 0, 1, 1 };

cust cset[NUM];											//custom集合
double distances[NUM][NUM];								//距离矩阵
int routes[NUM][NUM], num;								//路径,路径条数
double mil, totalTime, cap, remain;						//里程,总时间,容量,剩余货量

double tMil, tTime;
int tRoutes[NUM][NUM], tNum = NUM;

int criteria;											//路径初始化标准
int index;												//第几组参数

void vrptw(int count, int len);
void getResults(int count);

//求较大值
double max(double a, double b) {
	if (a > b)
		return a;
	else 
		return b;
}

//读取数据
void readInData(ifstream &fin)
{
	int no;
	string s;
	getline(fin, s);
	for (int i = 0; i < NUM; i++) {
		fin >> no;
		fin >> cset[i].x >> cset[i].y					//x, y坐标
			>> cset[i].demand							//需求量
			>> cset[i].rtime >> cset[i].dtime			//时间窗
			>> cset[i].stime;							//服务时间
		cset[i].btime = 0;								//服务开始时间
		cset[i].wtime = 0;								//等待时间
		cset[i].flag = true;							//标记是否routed
		cset[i].pos = 0;								//插入位置
		cset[i].c2 = 0;									//c2
	}
	fin >> cap;
}

//重置全局变量
void resetVariables()
{
	int i, j;
	if (num < tNum || (num == tNum && totalTime < tTime)) {
		for (i = 0; i < num; i++) {
			for (j = 0; j < NUM; j++)
				tRoutes[i][j] = routes[i][j];
		}
		tNum = num;
		tMil = mil;
		tTime = totalTime;
	}
	for (i = 0; i < NUM; i++) {
		cset[i].btime = 0;
		cset[i].flag = true;
		cset[i].pos = 0;
		cset[i].c2 = 0;
	}
	for (i = 0; i < num; i++) {
		for (j = 0; j < NUM; j++) {
			routes[i][j] = 0;
		}
	}
	totalTime = mil = num = 0;
}

//计算任意两custom间的距离
void calDistance(double distances[NUM][NUM])
{
	for (int i = 0; i < NUM; i++) {
		for (int j = 0; j < NUM; j++) {
			double deltaX = cset[i].x - cset[j].x;
			double deltaY = cset[i].y - cset[j].y;
			distances[i][j] = sqrt(deltaX * deltaX + deltaY * deltaY);
		}
	}
}

//获得farthest unrouted custom
int getFarthestUcust()
{
	int no = 0;
	double distance = 0;
	for (int i = 1; i < NUM; i++) {
		if (cset[i].flag && distances[0][i] > distance) {
			distance = distances[0][i];
			no = i;
		}
	}
	return no;
}

//获得earliest deadline custom
int getEarliestDcust()
{
	int no = 0;
	double deadline = 999999.0;
	for (int i = 1; i < NUM; i++) {
		if (cset[i].flag && cset[i].dtime < deadline) {
			deadline = cset[i].dtime;
			no = i;
		}
	}
	return no;
}

//计算到达客户j的时间
double calArriveTime(int j, int i)
{
	double pBtime;
	if (i == 0)
		pBtime = 0;
	else
		pBtime = cset[i].btime;
	return (pBtime + cset[i].stime + distances[i][j] * 1);
}

//计算客户j的服务开始时间
double calBtime(int j, int i)
{
	double arriveTime = calArriveTime(j, i);
	return max(arriveTime, cset[j].rtime);
}

//计算客户j的等待时间
double calWtime(int j, int i)
{
	double arriveTime = calArriveTime(j, i);
	if (arriveTime >= cset[j].rtime)
		return 0;
	else
		return cset[j].rtime - arriveTime;
}

//在count路径上的插入客户no
void insertCust(int count, int len, int no)
{
	int i, ts;
	for (i = len; i > cset[no].pos; i--) {
		routes[count][i] = routes[count][i-1];
	}
	routes[count][i] = no;
	cset[no].flag = false;
	for (; i < len + 1; i++) {
		ts = routes[count][i];
		cset[ts].wtime = calWtime(ts, routes[count][i-1]);
		cset[ts].btime = calBtime(ts, routes[count][i-1]); 
	}
	remain -= cset[no].demand;
	vrptw(count, len + 1);
}

//初始化一条新路径
void initialNewRoute(int count)
{
	int custNo;
	if (criteria == CRITERIA_DIST)
		custNo = getFarthestUcust();
	else
		custNo = getEarliestDcust();
	if (custNo != 0) {
		routes[count][0] = 0;
		routes[count][1] = 0;
		cset[custNo].pos = 1;
		remain = cap;
		insertCust(count, 2, custNo);
	}
	else
		getResults(count);
}

//c1函数
double func1(int count, int pos, int u)
{
	int p, n;
	double c11, c12;
	p = routes[count][pos - 1];
	n = routes[count][pos];
	c11 = distances[p][u] + distances[u][n] - mu[index] * distances[p][n];
	c12 = calBtime(n, u) - cset[n].btime;
	return alpha1[index] * c11 + alpha2[index] * c12;
}

//c2函数
double func2(int u, double c1)
{
	return lambda[index] * distances[0][u] - c1;
}

//验证是否满足time feasibility的充要条件
bool meetTCondition(int u, int pos, int count, int len)
{
	double pf;
	int prev, next, ts;
	prev = routes[count][pos-1];
	next = routes[count][pos];
	cset[u].btime = calBtime(u, prev);
	if (cset[u].btime > cset[u].dtime)
		return false;
	else {
		pf = calBtime(next, u) - cset[next].btime;
		if (cset[next].btime + pf > cset[next].dtime)
			return false;
		for (int r = pos + 1; r < len; r++) {
			ts = routes[count][r];
			pf = max(0, pf - cset[ts].wtime);
			if (cset[ts].btime + pf > cset[ts].dtime)
				return false;
		}
		return true;
	}
}

//找最合适的插入位置
void findBestPos(int count, int len, int custNo)
{
	int pos;
	double c1, c2;
	c1 = 999999.0;
	for (int i = 1; i < len; i++) {
		if (!meetTCondition(custNo, i, count, len) || remain < cset[custNo].demand)
			continue;
		else {
			if (func1(count, i, custNo) < c1) {
				c1 = func1(count, i, custNo);
				pos = i;
			}
		}
	}
	if (c1 < 999999.0) {
		c2 = func2(custNo, c1);
		cset[custNo].pos = pos;
		cset[custNo].c2 = c2;
	}
}

//找最适合插入的custom
int findBestCust(int count, int len)
{
	int custNo = 0;
	double tmp = -999999.0;
	for (int i = 1; i < NUM; i++) {
		if (cset[i].flag) {
			//先清除上次计算的数据
			cset[i].pos = 0;
			cset[i].c2 = 0;
			findBestPos(count, len, i);
		}
	}
	for (int i = 1; i < NUM; i++) {
		if (cset[i].flag && cset[i].pos != 0) {
			if (cset[i].c2 > tmp) {
				tmp = cset[i].c2;
				custNo = i;
			}
		}
	}
	return custNo;
}

//统计结果
void getResults(int count)
{
	int i, j, a, b;
	//double tmp = 0, time;
	num = count;
	for (i = 0; i < num; i++) {
		j = 1;
		while (j < 3 || routes[i][j - 1] != 0) {
			a = routes[i][j - 1];
			b = routes[i][j];
			mil += distances[a][b];
			j++;
		}
		totalTime += cset[a].btime + cset[a].stime + distances[a][b];
		//time = cset[a].btime + cset[a].stime + distances[a][b];
		//if (time > tmp)
			//tmp = time;
	}
	//totalTime = tmp;
	resetVariables();
}

//输出最终结果
void putOutData(ofstream &fout, ofstream &fjson, double runtime)
{
	int i, j;
	string sep;
	double x, y;
	fout.open("result.out");
	fjson.open("routes.json");
	fout << "tnum: " << tNum << endl
		<< "tMil: " << tMil << endl
		<< "runtime: " << runtime << endl;
	fjson << "{" << endl;
	fjson << "routes:" << endl << "[" << endl;
	for (i = 0; i < tNum; i++) {
		j = 0;
		fjson << "[";
		while (j < 2 || tRoutes[i][j] != 0) {
			fjson << tRoutes[i][j] << ", ";
			j++;
		}
		if (i == tNum - 1) 
			sep = "]";
		else 
			sep = "],";
		fjson << tRoutes[i][j] << sep << endl;
	}
	fjson << "]," << endl;
	fjson << "cset:" << endl << "[" << endl;
	for (i = 0; i < NUM; i++) {
		if (i == NUM - 1)
			sep = "]";
		else
			sep = "],";
		//将x映射到114.0-114.5,y映射到22.5-23.0
		x = cset[i].x / 100 * (114.5 - 114.0) + 114.0;
		y = cset[i].y / 100 * (23.0 -22.5) + 22.5;
		fjson << "[" << x << ", " << y  << sep << endl;
	}
	fjson << "]" << endl << "}" << endl;
}

void vrptw(int count, int len)
{
	int custNo;
	if (count == 0 && len == 0)
		initialNewRoute(count);
	else {
		custNo = findBestCust(count, len);
		if (custNo == 0)
			initialNewRoute(count + 1);
		else
			insertCust(count, len, custNo);
	}
}

int main(int argc, char** argv)
{
	ifstream fin;
	ofstream fout, fjson;
	clock_t start, finish;
	start = clock();
	if (argc != 2) {
		cout << "Please use command like: vrptw c101.in." << endl;
		return 1;
	}

	fin.open(argv[1]);
	//fin.open("c201.in");
	if (!fin.is_open()) {
		cout << "Open file error! Application will exit." << endl;
		return 2;
	}
	readInData(fin);
	calDistance(distances);
	for (int i = 0; i < 8; i++) {
		criteria = i / 4;
		index = i % 4;
		vrptw(0, 0);
	}
	finish = clock();
	putOutData(fout, fjson, (double)(finish - start) / CLOCKS_PER_SEC);
	return 0;
}

调用百度地图接口

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
#l-map{height:100%;width:78%;float:left;border-right:2px solid #bcbcbc;}
#r-result{height:100%;width:20%;float:left;}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=88xDBIvgExozgbthhbFwuHlg"></script>
<title>VRPTW路径</title>
</head>
<body>
<input type="file" id="files" name="files[]" multiple />
<div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
  function handleFileSelect(evt) {
    var i, f;
    var files = evt.target.files;         // FileList object

    // Loop through the FileList.
    for (i = 0; f = files[i]; i++) {
      var reader = new FileReader();
      // Closure to capture the file information.
      reader.onload = (function(theFile) {
        return function(e) {
          var string = e.target.result;
          var obj = eval ("(" + string + ")");
          var routes = obj.routes;
          var cset = obj.cset;
          var points = new Array();

          // 百度地图API功能
		      var map = new BMap.Map("allmap");
    		  var cPoint = new BMap.Point(114.25, 22.75);
    		  map.centerAndZoom(cPoint, 12);
          // 创建标注
          function addMarker(point) {
            var marker = new BMap.Marker(point);
            map.addOverlay(marker);
          };
          // 创建路径
          function addPolyline(route, flag) {
            var color;
            if (flag == 0)
              color = "blue";
            else if (flag == 1)
              color = "green";
            else 
              color = "red"
            var polyline = new BMap.Polyline(route, {strokeColor:color, strokeWeight:1.8, strokeOpacity:0.5});
            map.addOverlay(polyline);
          };
          for (i = 0; i < 101; i++) {
            points[i] = new BMap.Point(cset[i][0], cset[i][1]);
            addMarker(points[i]);
          }
          for (i in routes) {
            var route =  new Array();
            for (var j in routes[i]) {
              route[j] = points[routes[i][j]];
            }
            addPolyline(route, i % 3);
          }
        };
      })(f);

      reader.readAsText(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

    原文作者:蚁群算法
    原文地址: https://blog.csdn.net/jxiaoyu_ph/article/details/18908715
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞