Java实现vrptw遗传算法
由于参加了一个物流设计比赛,自己不会matlab,在网上找不到Java的遗传算法,于是自己写了一个阉割版,代码有点乱来不及整理,很多写了的功能也没用上,还有很多注释在里面,图一乐看一看就好。
先写一个需求点的类存放相关信息
public class Customers {
int index; //序号
double demands; //顾客需求
double earliest; //最早被服务时间
double latest; //最晚被服务时间
Customers next; //下一个被服务的节点
Customers last; //上一个被服务的节点
double time; //路程耗费时间
double s; //服务时间
double x; //横坐标
double y; //纵坐标
public Customers(int index,double demands, double earliest, double latest, double d, double e, double f) {
super();
this.index = index;
this.demands = demands;
this.earliest = earliest;
this.latest = latest;
this.s = d;
this.x = e;
this.y = f;
}
public Customers(double e, double f) {
this.x = e;
this.y = f;
}
//获得距离dot点的距离
public double get(Customers dot) {
return Math.sqrt(((this.x-dot.x)*(this.x-dot.x)+(this.y-dot.y)*(this.y-dot.y)));
}
//获取头节点
public Customers getRoot() {
if(this.last == null) {
return this;
}else {
return this.last.getRoot();
}
}
//获取当前链的时间耗费
public double getAllTime() {
Customers tmp = this.getRoot();
double allTime = 0;
allTime += (tmp.time+s);
while(tmp.next != null) {
tmp = tmp.next;
allTime += (tmp.time+s);
}
return allTime;
}
}
主体片段
package VRPTW;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
// 假定车辆载重为 can
static double can = 6;
// 假定车辆速度为 speed
static double speed = 1;
// 创建配送中心和客户点
static Customers storehouse = new Customers("陶家岭医药物流园",0, 0);
// 序号,需求量,最早到达时间,最晚到达时间,服务时间,x坐标,y坐标
static Customers c01 = new Customers(1,"华中科技大学同济医学院附属普爱医院", 2, 8, 12, 0.2, 0.023, 0.088);
static Customers c02 = new Customers(2,"武汉中医医院", 3, 8, 10, 0.2, 0.03, -0.047);
static Customers c03 = new Customers(3,"泰康同济武汉医院", 1, 8, 11, 0.2, 0.075, 0.058);
static Customers c04 = new Customers(4,"武汉仁爱医院", 0.3, 8, 12, 0.2, 0.059, -0.04);
static Customers c05 = new Customers(5,"华中科技大学同济医学院附属同济医院", 2.5, 8, 10, 0.2, 0.103, 0.065);
static Customers c06 = new Customers(6,"武汉市第一医院", 5, 8, 10, 0.2, 0.121, 0.052);
static Customers c07 = new Customers(7,"武汉市中心医院", 3.5, 8, 9, 0.2, 0.159, 0.045);
static Customers c08 = new Customers(8,"武汉大学人民医院", 4, 8, 11, 0.2, 0.165, -0.018);
static Customers c09 = new Customers(9,"武汉市第三医院(首义院区)", 1, 8, 10.5, 0.2, 0.171, -0.009);
static Customers c10 = new Customers(10,"武警湖北省总队医院", 0.5, 8, 12, 0.2, 0.187, -0.005);
static Customers c11 = new Customers(11,"中国人民解放军中部战区总医院", 1.7, 8, 11, 0.2, 0.237, -0.025);
static Customers c12 = new Customers(12,"武汉大学中南医院", 2.2, 8, 12, 0.2, 0.25, 0.017);
static Customers c13 = new Customers(13,"武汉市汉阳医院", 4, 8, 11, 0.2, 0.08, 0.008);
static Customers c14 = new Customers(14,"武汉第三医院光谷区", 0.8, 8, 12, 0.2, 0.343, 0.086);
static List<int[]> route;
// 已访问的点
// static List<Integer> visited = new ArrayList<>();
// 未访问的点
static List<Integer> unvisited = new ArrayList<>();
// 5辆车(不一定全部用到)
static int[] car01 = new int[15];
static int[] car02 = new int[15];
static int[] car03 = new int[15];
static int[] car04 = new int[15];
static int[] car05 = new int[15];
static int[] car06 = new int[15];
// //存储方案
static Map<Integer, Double> map = new HashMap<>();
public static void main(String[] args) {
// //初始化为访问的点
// unvisited.add(1);
// unvisited.add(2);
// unvisited.add(3);
// unvisited.add(4);
// unvisited.add(5);
// unvisited.add(6);
// unvisited.add(7);
// unvisited.add(8);
// unvisited.add(9);
// unvisited.add(10);
// unvisited.add(11);
// unvisited.add(12);
// unvisited.add(13);
// unvisited.add(14);
// //初始化五辆车的起始点(配送中心)
// car01[0] = 0;
// car02[0] = 0;
// car03[0] = 0;
// car04[0] = 0;
// car05[0] = 0;
// car06[0] = 0;
// init()的正确步骤如下:
// System.out.println(getName(getCar()));
// addDot(car01,1);
// showAll();
//
// System.out.println(getName(getCar()));
// addDot(car01,2);
// showAll();
//
// System.out.println(getName(getCar()));
// addDot(car01,3);
// showAll();
//
// System.out.println(getName(getCar()));
// addDot(car01,4);
// showAll();
//
// System.out.println(canTake(car01,5));
// System.out.println(canTake(car01,6));
// System.out.println(canTake(car01,7));
// System.out.println(canTake(car01,8));
// System.out.println(canTake(car01,9));
// System.out.println(canTake(car01,10));
//
// System.out.println(getName(getCar()));
// addDot(car01,10);
// showAll();
//
// System.out.println(getName(getCar()));
测试所写的方法
// car01[0] = 0;
// car01[1] = 3;
// car01[2] = 6;
//
// System.out.println(getLength(car01));
// System.out.println(isOverCan(car01));
// System.out.println(getLoaded(car01));
// System.out.println(getTime(car01));
//
// System.out.println(canTake(car01,10));
// System.out.println(canTake(car01,8));
//
// System.out.println(getName(getCar()));
// 生成初始方案
// init();
// 查看
// showAll();
// System.out.println(getAllTime());
// 遗传一次
// inherit();
// 遗传成功一次
// inherit();
// 查看
// showAll();
// System.out.println(getAllTime());
// init();
// showAll();
// System.out.println(getAllTime());
// int i=0;
// while(i<10000) {
// inherit();
// showAll();
// System.out.println(getAllTime());
// i++;
// }
HaHa();
// //手动启动
// reset();
// List<int[]> l1 = finalOp();
Double d1 = new Double(listTime(l1));
// printList(l1);
//
//
// reset();
// List<int[]> l2 = finalOp();
Double d2 = new Double(listTime(l2));
// printList(l2);
//
//
// reset();
// List<int[]> l3 = finalOp();
Double d3 = new Double(listTime(l3));
// printList(l3);
// for(Map.Entry<Double, List<int[]>> entry : map.entrySet()) {
// printList(entry.getValue());
// }
// 时间查看
// System.out.println(getAllTime());
// 查看目前车辆安排是否合法
// System.out.println(isLeagel(car01));
// System.out.println(isLeagel(car02));
// System.out.println(isLeagel(car03));
// System.out.println(isLeagel(car04));
// System.out.println(isLeagel(car05));
// System.out.println(isLeagel(car06));
// car01[6] = 7;
// System.out.println(isLeagel(car01));
// car02[4] = 6;
// System.out.println(isLeagel(car02));
}
// 根据数字获得对应客户点对象
public static Customers getCustomer(int i) {
switch (i) {
case 0:
return storehouse;
case 1:
return c01;
case 2:
return c02;
case 3:
return c03;
case 4:
return c04;
case 5:
return c05;
case 6:
return c06;
case 7:
return c07;
case 8:
return c08;
case 9:
return c09;
case 10:
return c10;
case 11:
return c11;
case 12:
return c12;
case 13:
return c13;
case 14:
return c14;
default:
return null;
}
}
// 判断车量是否是空任务
public static boolean isFree(int[] arr) {
int i = 0;
for (int j = 0; j < arr.length; j++) {
if (arr[j] != 0) {
i++;
}
}
if (i == 0) {
return true;
} else {
return false;
}
}
// 得到车数组的真实长度(因为没有客户点的数组后面是0)
public static int getLength(int[] arr) {
int i = 14;
for (; i > 0; i--) {
if (arr[i] != 0) {
break;
}
}
return i + 1;
}
// 检测是否超载
public static boolean isOverCan(int[] arr) {
double allLoad = 0;
for (int i = 0; i < getLength(arr); i++) {
Customers tmp = getCustomer(arr[i]);
allLoad += tmp.demands;
}
if (allLoad > can) {
// 超载返回false
return false;
} else {
// 不超载返回true
return true;
}
}
// 得到目前已经装载的量
public static double getLoaded(int[] arr) {
double allLoad = 0;
for (int i = 0; i < getLength(arr); i++) {
Customers tmp = getCustomer(arr[i]);
allLoad += tmp.demands;
}
return allLoad;
}
// 检测是否能接受下一个点
public static boolean canTake(int[] arr, int i) {
if (getLength(arr) > 1) {
Customers last = getCustomer(arr[getLength(arr) - 1]);
Customers tmp = getCustomer(i);
Customers first = getCustomer(arr[1]);
double allTime = getTime(arr);
// 先判断载重能否接受
if (getLoaded(arr) + tmp.demands > can) {
return false;
} else {
// 判断时间能否接受
double distance = Math.sqrt((last.x - tmp.x) * (last.x - tmp.x) + (last.y - tmp.y) * (last.y - tmp.y));
double time = distance / speed;
if (first.earliest + time + allTime > tmp.latest) {
return false;
} else {
return true;
}
}
} else {
return true;
}
}
// 得到目前车已经花费的时间
public static double getTime(int[] arr) {
double allTime = 0;
for (int i = 1; i < getLength(arr); i++) {
Customers cFrom = getCustomer(arr[i - 1]);
Customers cTo = getCustomer(arr[i]);
double distance = Math.sqrt((cFrom.x - cTo.x) * (cFrom.x - cTo.x) + (cFrom.y - cTo.y) * (cFrom.y - cTo.y));
double time = distance / speed;
allTime += time;
}
allTime += 0.2 * (getLength(arr) - 1);
return allTime;
}
// 获取当前仍然可以接受任务的车辆
public static int[] getCar() {
for (int i : unvisited) {
if (canTake(car01, i)) {
// 测试
// System.out.println("car01");
// show(car01);
// System.out.println(getLength(car01));
// System.out.println(unvisited);
return car01;
}
}
for (int i : unvisited) {
if (canTake(car02, i)) {
return car02;
}
}
for (int i : unvisited) {
if (canTake(car03, i)) {
return car03;
}
}
for (int i : unvisited) {
if (canTake(car04, i)) {
return car04;
}
}
for (int i : unvisited) {
if (canTake(car05, i)) {
return car05;
}
}
for (int i : unvisited) {
if (canTake(car06, i)) {
return car06;
}
}
return null;
}
// 根据数组获得对应的车辆名称
public static String getName(int[] arr) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car01[i]) {
break;
}
if (arr[getLength(car01) - 1] == car01[getLength(car01) - 1]) {
return "car01";
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car02[i]) {
break;
}
if (arr[getLength(car02) - 1] == car02[getLength(car02) - 1]) {
return "car02";
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car03[i]) {
break;
}
if (arr[getLength(car03) - 1] == car03[getLength(car03) - 1]) {
return "car03";
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car04[i]) {
break;
}
if (arr[getLength(car04) - 1] == car04[getLength(car04) - 1]) {
return "car04";
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car05[i]) {
break;
}
if (arr[getLength(car05) - 1] == car05[getLength(car05) - 1]) {
return "car05";
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != car06[i]) {
break;
}
if (arr[getLength(car06) - 1] == car06[getLength(car06) - 1]) {
return "car06";
}
}
return null;
}
// 建立初始的路线
public static void init() {
// 因为addDot方法会删除unvisited集合里的数据,在遍历集合时不能执行删除操作,不然会报错
// 所以创建一个新的集合,与unvisited值相等
List<Integer> tmp = new ArrayList<>();
for (int i : unvisited) {
tmp.add(i);
}
while (!unvisited.isEmpty()) {
int[] tp = getCar();
for (int i : tmp) {
if (canTake(tp, i)) {
addDot(tp, i);
}
}
tmp = new ArrayList<>();
for (int i : unvisited) {
tmp.add(i);
}
}
}
// 重置
public static void reset() {
// 初始化为访问的点
unvisited.clear();
unvisited.add(1);
unvisited.add(2);
unvisited.add(3);
unvisited.add(4);
unvisited.add(5);
unvisited.add(6);
unvisited.add(7);
unvisited.add(8);
unvisited.add(9);
unvisited.add(10);
unvisited.add(11);
unvisited.add(12);
unvisited.add(13);
unvisited.add(14);
// 初始化五辆车的起始点(配送中心)
for (int i = 0; i < car01.length; i++) {
car01[i] = 0;
car02[i] = 0;
car03[i] = 0;
car04[i] = 0;
car05[i] = 0;
car06[i] = 0;
}
}
// 添加客户点
public static void addDot(int[] arr, int num) {
// 如果车辆没有起始点,规定起始点为0(即配送中心)
if (getLength(arr) == 0) {
arr[0] = 0;
}
arr[getLength(arr)] = num;
Integer n = num;
// 加入后要从未访问的集合中弹出该加入的点
unvisited.remove(n);
}
// 数组显示
public static void show(int arr[]) {
String name = getName(arr);
String str = name + ":";
for (int i = 0; i < getLength(arr); i++) {
str += arr[i] + " ";
}
System.out.println(str);
}
// 显示目前已经有路线的所有车辆路径
public static void showAll() {
if (getLength(car01) > 1) {
show(car01);
}
if (getLength(car02) > 1) {
show(car02);
}
if (getLength(car03) > 1) {
show(car03);
}
if (getLength(car04) > 1) {
show(car04);
}
if (getLength(car05) > 1) {
show(car05);
}
if (getLength(car06) > 1) {
show(car06);
}
}
// 得到所有已经有路线的车辆数量
public static int allNum() {
int num = 0;
if (getLength(car01) > 1) {
num++;
}
if (getLength(car02) > 1) {
num++;
}
if (getLength(car03) > 1) {
num++;
}
if (getLength(car04) > 1) {
num++;
}
if (getLength(car05) > 1) {
num++;
}
if (getLength(car06) > 1) {
num++;
}
return num;
}
// 根据数字得到对应的车辆数组
public static int[] getTheCar(int i) {
switch (i) {
case 1:
return car01;
case 2:
return car02;
case 3:
return car03;
case 4:
return car04;
case 5:
return car05;
case 6:
return car06;
default:
return null;
}
}
/
// 遗传算法///
/
// 获取方案的总时间
public static double getAllTime() {
double t1 = getTime(car01);
double t2 = getTime(car02);
double t3 = getTime(car03);
double t4 = getTime(car04);
double t5 = getTime(car05);
double t6 = getTime(car06);
// System.out.println(t1);
// System.out.println(t2);
// System.out.println(t3);
// System.out.println(t4);
// System.out.println(t5);
// System.out.println(t6);
return t1 + t2 + t3 + t4 + t5 + t6;
}
// 根据选定的范围剪切数组
public static int[] sub(int[] arr, int from, int to) {
int[] tmp = new int[arr.length];
for (int i = from; i < to; i++) {
tmp[i] = arr[i];
}
return tmp;
}
// 检测该车路径是否都合法
public static boolean isLeagel(int[] arr) {
if (getLength(arr) > 1) {
boolean flag = true;
for (int i = 0; i < getLength(arr) - 1; i++) {
int[] tmp = sub(arr, 0, i + 1);
if (!canTake(tmp, arr[i + 1])) {
flag = false;
break;
}
}
return flag;
} else {
return true;
}
}
// 数组随机单位元素交换并检测是否合法,不合法则返回
public static boolean exchange(int[] arr1, int[] arr2) {
double ftime = getTime(arr1) + getTime(arr2);
int[] re1 = new int[arr1.length];
int[] re2 = new int[arr2.length];
for (int i = 0; i < arr1.length; i++) {
re1[i] = arr1[i];
}
// System.out.println();
// System.out.println("re");
// show(re1);
// System.out.println();
for (int i = 0; i < arr2.length; i++) {
re2[i] = arr2[i];
}
// System.out.println();
// System.out.println("re");
// show(re2);
// System.out.println();
int num1 = getLength(arr1) - 1;
int num2 = getLength(arr2) - 1;
int ran1 = (int) (num1 * Math.random()) + 1;
int ran2 = (int) (num2 * Math.random()) + 1;
int tmp = arr1[ran1];
arr1[ran1] = arr2[ran2];
arr2[ran2] = tmp;
if (isLeagel(arr1) && isLeagel(arr2)) {
// System.out.println(isLeagel(arr1));
// System.out.println(isLeagel(arr2));
// System.out.println(getTime(arr1));
// System.out.println(getTime(arr2));
if (getTime(arr1) + getTime(arr2) < ftime) {
// System.out.println("交换了");
return true;
} else {
for (int i = 0; i < re1.length; i++) {
arr1[i] = re1[i];
}
for (int i = 0; i < re2.length; i++) {
arr2[i] = re2[i];
}
return false;
}
} else {
for (int i = 0; i < re1.length; i++) {
arr1[i] = re1[i];
}
for (int i = 0; i < re2.length; i++) {
arr2[i] = re2[i];
}
return false;
}
}
// 把一个数字插到数组中间
public static void insert(int[] arr, int index, int num) {
int[] tmp = new int[arr.length];
for (int i = 0; i < index + 1; i++) {
tmp[i] = arr[i];
}
tmp[index + 1] = num;
for (int i = index + 2; i < getLength(arr) + 1; i++) {
tmp[i] = arr[i - 1];
}
for (int i = 0; i < tmp.length; i++) {
arr[i] = tmp[i];
}
}
// 检查是否可以减少任务最少的车辆的任务,可以则执行
public static boolean canRecedeCar() {
int[] aim = getTheCar(allNum());
int length = getLength(aim);
for (int i = 1; i < length; i++) {
int num = aim[i];
for (int j = 1; j < allNum(); j++) {
int[] tt = getTheCar(j);
int[] tmp = new int[tt.length];
for (int k = 0; k < tt.length; k++) {
tmp[k] = tt[k];
}
for (int k = 0; k < getLength(tt); k++) {
insert(tmp, k, num);
if (isLeagel(tmp)) {
System.out.println(getName(aim) + "的任务" + num + "点交给了" + getName(tt));
for (int l = 0; l < tmp.length; l++) {
tt[l] = tmp[l];
}
return true;
} else {
for (int u = 0; u < tt.length; u++) {
tmp[u] = tt[u];
}
}
}
}
}
return false;
}
// 从有路径的车辆中随机选出两辆遗传交换
public static void inherit() {
int num1 = (int) (allNum() * Math.random()) + 1;
int num2 = (int) (allNum() * Math.random()) + 1;
while (num1 == num2) {
num2 = (int) (allNum() * Math.random()) + 1;
}
int[] tmp1 = getTheCar(num1);
int[] tmp2 = getTheCar(num2);
exchange(tmp1, tmp2);
canRecedeCar();
}
// 将迭代结果存储在一个List中
public static List<int[]> finalOp() {
// reset();
init();
int i = 0;
while (i < 10000) {
inherit();
System.out.println("迭代--" + i);
showAll();
System.out.println(getAllTime());
i++;
}
List<int[]> list = new ArrayList<int[]>();
for (int j = 1; j <= allNum(); j++) {
list.add(getTheCar(j));
}
return list;
}
// 获得List的运输方案的时间并返回
public static double listTime(List<int[]> list) {
double time = 0;
for (int[] a : list) {
time += getTime(a);
}
return time;
}
// 输出List里面的方案
public static void printList(List<int[]> list) {
System.out.println("最终方案:");
for (int[] a : list) {
StringBuilder route = new StringBuilder("");
String name = getName(a);
route.append(name+":");
for(int i = 0;i<getLength(a);i++) {
route.append(getCustomer(a[i]).name+"-->");
}
route.append(storehouse.name);
System.out.println(route);
}
System.out.println("car01载重为:"+getLoaded(car01)+"单位 "+"car01时间为:"+getTime(car01)+"单位");
System.out.println("car02载重为:"+getLoaded(car02)+"单位 "+"car02时间为:"+getTime(car02)+"单位");
System.out.println("car03载重为:"+getLoaded(car03)+"单位 "+"car03时间为:"+getTime(car03)+"单位");
System.out.println("car04载重为:"+getLoaded(car04)+"单位 "+"car04时间为:"+getTime(car04)+"单位");
System.out.println("car05载重为:"+getLoaded(car05)+"单位 "+"car05时间为:"+getTime(car05)+"单位");
System.out.println("car06载重为:"+getLoaded(car06)+"单位 "+"car06时间为:"+getTime(car06)+"单位");
System.out.println("总路程为:" + listTime(list) + "单位");
}
// 最终
public static void HaHa() {
reset();
List<int[]> list = finalOp();
System.out.println();
System.out.println();
printList(list);
reset();
init();
System.out.println("初始方案:");
for (int i = 1; i <= allNum(); i++) {
StringBuilder route = new StringBuilder("");
int[] arr = getTheCar(i);
String name = getName(arr);
route.append(name+":");
for(int j=0;j<getLength(arr);j++) {
route.append(getCustomer(arr[j]).name+"-->");
}
route.append(storehouse.name);
System.out.println(route);
}
System.out.println("car01载重为:"+getLoaded(car01)+"单位 "+"car01时间为:"+getTime(car01)+"单位");
System.out.println("car02载重为:"+getLoaded(car02)+"单位 "+"car02时间为:"+getTime(car02)+"单位");
System.out.println("car03载重为:"+getLoaded(car03)+"单位 "+"car03时间为:"+getTime(car03)+"单位");
System.out.println("car04载重为:"+getLoaded(car04)+"单位 "+"car04时间为:"+getTime(car04)+"单位");
System.out.println("car05载重为:"+getLoaded(car05)+"单位 "+"car05时间为:"+getTime(car05)+"单位");
System.out.println("car06载重为:"+getLoaded(car06)+"单位 "+"car06时间为:"+getTime(car06)+"单位");
System.out.println("总路程为:" + listTime(list) + "单位");
}
}