Java实现vrptw遗传算法

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) + "单位");
	}
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值