遗传算法求解TSP及其变式
刚刚接触遗传算法,主要学习的是以下几位老师的文章(抱拳),链接附上:
https://blog.csdn.net/u010451580/article/details/51178225
https://blog.csdn.net/wangqiuyun/article/details/12838903
写这篇文章主要是系统地整理一下我这几天学到了算法,所以内容不多。
1.遗传算法简介
遗传算法(Genetic Algorithm, GA)起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法,借鉴了达尔文的进化论和孟德尔的遗传学说。
算法是将初始解构成初始种群,然后不断遗传、进化、变异,最终从中挑选出最优个体,应该算是基于大数据的。
有三种基本算子:选择,交叉,变异,
遗传算法的实施步骤如下(以目标函数求最小为例)。
第一步:初始化 t←0进化代数计数器;T是最大进化代数;随机生成M个个体作为初始群体P(t);
第二步:个体评价 计算P(t)中各个个体的适应度;(即评估个体好坏的一个指标)
第三步:选择运算 将选择算子作用于群体;(类似于物竞天择,适者生存)
第四步:交叉运算 将交叉算子作用于群体;(两个体交叉繁殖出新个体)斜体样式
第五步:变异运算 将变异算子作用于群体,并通过以上运算得到下一代群体P(t + 1);(自身变异形成新个体)
第六步:终止条件判断 t≦T:t← t+1 转到步骤2;t>T:终止 输出解。
常见的选择策略:
最常见的是赌轮选择方法,本质是个体被选中的概率与适应度成正比。这里选择的时候会用到累计概率,即计算出个体的适应度后,求出个体适应度占总适应度的一个比例,如个体1、个体2、个体3的适应度分别为f1,f2,f3,总适应度sumf = f1+f2+f3.则个体1、2、3的累计概率分别为f1/sumf, (f1+f2)/sumf, (f1+f2+f3)/sumf。最后一个数必然为1,则构成一个0-1的轮盘,随机数落在哪个范围,即选择对应个体作为新种群的一员。
那么具体如何选择,如何交叉?且看一下大神整理的:
https://www.cnblogs.com/legend1130/p/5333087.html
常见交叉策略:
https://blog.csdn.net/ztf312/article/details/82793295
其实感觉算法还是要结合一下具体事例(代码)一起看的,刚开始看算法似懂非懂,雾里看花的感觉,还是看了一遍别人写的具体代码才拨云见月。
2.具体应用——TSP问题
TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
1、
基本思路:
1》初始化:随机生成scale条路径放入oldpopulation,(城市作为编号,编码表示路径。scale为种群的规模,每一条路径为一个个体)
2》算适应度:路径的长度越短,适应度(fitness)最高
3》挑选出适应度最高的路径放入newpopulation,若优于之前的best_tour,则更新best_tour
4》计算种群中个个体的累计概率,用赌轮选择法挑选出下一代放入newpopulation
5》对newpopulation进行交叉
6》对newpopulation进行变异
7》将newpopulation—>oldpopulation,
8》将重复进行2-7
代码附上:(和wangqiuyun博主不同的是我的代码所需数据是自己给的(也可自己文件读写),八个城市的距离矩阵(无向图,所以是对称矩阵)
private int[][] distance =
{{0, 300, 360, 210, 590, 475 , 500, 690},
{300, 0 ,380, 270, 230, 285, 200, 390},
{360, 380, 0 ,510 ,230, 765, 580, 770},
{210, 270 , 510, 0, 470, 265, 450, 640},
{590, 230, 230, 470 ,0, 515 , 260, 450},
{475, 285, 765, 265, 515, 0 ,460, 650},
{500, 200 , 580 , 450 ,260 ,460 ,0 ,190},
{690, 390 ,770, 640 ,450, 650 ,190, 0}}; )
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random; public class GA { private int scale;// 种群规模 private int cityNum; // 城市数量,染色体长度 private int MAX_GEN; // 运行代数 private int start = 0;private int end = 7;private int[][] distance = {{0, 300, 360, 210, 590, 475 , 500, 690},{10000, 0 ,380, 270, 230, 285, 200, 390},{10000, 380, 0 ,510 ,230, 765, 580, 770},{10000, 270 , 510, 0, 470, 265, 450, 640},{10000, 230, 230, 470 ,0, 515 , 260, 450},{10000, 285, 765, 265, 515, 0 ,460, 650},{10000, 200 , 580 , 450 ,260 ,460 ,0 ,190},{10000, 10000 ,10000, 10000 ,10000, 10000 ,10000, 0}}; // 距离矩阵 */ private int bestT;// 最佳出现代数 private int bestLength; // 最佳长度 private int[] bestTour; // 最佳路径 // 初始种群,父代种群,行数表示种群规模,一行代表一个个体,即染色体,列表示染色体基因片段 private int[][] oldPopulation; private int[][] newPopulation;// 新的种群,子代种群 private int[] fitness;// 种群适应度,表示种群中各个个体的适应度 private float[] Pi;// 种群中各个个体的累计概率 private float Pc;// 交叉概率 private float Pm;// 变异概率 private int t;// 当前代数 private Random random; public GA() { } /** * constructor of GA * * @param s * 种群规模 * @param n * 城市数量 * @param g * 运行代数 * @param c * 交叉率 * @param m * 变异率 * **/ public GA(int s, int n, int g, float c, float m) { scale = s; cityNum = n; MAX_GEN = g; Pc = c; Pm = m; } // 给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默 @SuppressWarnings("resource") /** * 初始化GA算法类 * @param filename 数据文件名,该文件存储所有城市节点坐标数据 * @throws IOException */ private void init(String filename) throws IOException { // 读取数据 /*int[] x; int[] y; String strbuff; BufferedReader data = new BufferedReader(new InputStreamReader( new FileInputStream(filename))); distance = new int[cityNum][cityNum]; x = new int[cityNum]; y = new int[cityNum]; for (int i = 0; i < c ityNum; i++) { // 读取一行数据,数据格式1 6734 1453 strbuff = data.readLine(); // 字符分割 String[] strcol = strbuff.split(" "); x[i] = Integer.valueOf(strcol[1]);// x坐标 y[i] = Integer.valueOf(strcol[2]);// y坐标 } // 计算距离矩阵 // ,针对具体问题,距离计算方法也不一样,此处用的是att48作为案例,它有48个城市,距离计算方法为伪欧氏距离,最优值为10628 for (int i = 0; i < cityNum - 1; i++) { distance[i][i] = 0; // 对角线为0 for (int j = i + 1; j < cityNum; j++) { double rij = Math .sqrt(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])) / 10.0); // 四舍五入,取整 int tij = (int) Math.round(rij); if (tij < rij) { distance[i][j] = tij + 1; distance[j][i] = distance[i][j]; } else { distance[i][j] = tij; distance[j][i] = distance[i][j]; } } } distance[cityNum - 1][cityNum - 1] = 0; */bestLength = Integer.MAX_VALUE; bestTour = new int[cityNum + 1]; bestT = 0; t = 0; newPopulation = new int[scale][cityNum]; oldPopulation = new int[scale][cityNum]; fitness = new int[scale]; Pi = new float[scale]; random = new Random(System.currentTimeMillis()); /* * for(int i=0;i<cityNum;i++) { for(int j=0;j<cityNum;j++) { * System.out.print(distance[i][j]+","); } System.out.println(); } */ // 初始化种群 } // 初始化种群 void initGroup() { int i, j, k; // Random random = new Random(System.currentTimeMillis()); for (k = 0; k < scale; k++)// 种群数 { oldPopulation[k][0] = random.nextInt(65535) % cityNum; for (i = 1; i < cityNum;)// 染色体长度 { oldPopulation[k][i] = random.nextInt(65535) % cityNum; for (j = 0; j < i; j++) { if (oldPopulation[k][i] == oldPopulation[k][j]) { break; } } if (j == i) { i++; } } } /* * for(i=0;i<scale;i++) { for(j=0;j<cityNum;j++) { * System.out.print(oldPopulation[i][j]+","); } System.out.println(); } */ } //返回路径长度public int evaluate(int[] chromosome) { // 0123 int len = 0; // 染色体,起始城市,城市1,城市2...城市n for (int i = 1; i < cityNum; i++) { len += distance[chromosome[i - 1]][chromosome[i]]; } // 城市n,起始城市 // len += distance[chromosome[cityNum - 1]][chromosome[0]]; return len; } // 计算种群中各个个体的累积概率,前提是已经计算出各个个体的适应度fitness[max],作为赌轮选择策略一部分,Pi[max] void countRate() { int k; double sumFitness = 0;// 适应度总和 double[] tempf = new double[scale]; for (k = 0; k < scale; k++) { tempf[k] = 10.0 / fitness[k]; //适应度越小,temp越大,即temp与长度成反比sumFitness += tempf[k]; } Pi[0] = (float) (tempf[0] / sumFitness); for (k = 1; k < scale; k++) { Pi[k] = (float) (tempf[k] / sumFitness + Pi[k - 1]); //累积概率} /* * for(k=0;k<scale;k++) { System.out.println(fitness[k]+" "+Pi[k]); } */ } // 挑选某代种群中适应度最高的个体,直接复制到子代中 (即路径长度的值最低) // 前提是已经计算出各个个体的适应度Fitness[max] public void selectBestGh() { int k, i, maxid; int maxevaluation; maxid = 0; maxevaluation = fitness[0]; for (k = 1; k < scale; k++) { if (maxevaluation > fitness[k]) { maxevaluation = fitness[k]; maxid = k; } } if (bestLength > maxevaluation) { bestLength = maxevaluation; bestT = t;// 最好的染色体出现的代数; for (i = 0; i < cityNum; i++) { bestTour[i] = oldPopulation[maxid][i]; } } // System.out.println("代数 " + t + " " + maxevaluation); // 复制染色体,k表示新染色体在种群中的位置,kk表示旧的染色体在种群中的位置 copyGh(0, maxid);// 将当代种群中适应度最高的染色体k复制到新种群中,排在第一位0 } // 复制染色体,k表示新染色体在种群中的位置,kk表示旧的染色体在种群中的位置 public void copyGh(int k, int kk) { int i; for (i = 0; i < cityNum; i++) { newPopulation[k][i] = oldPopulation[kk][i]; } } // 赌轮选择策略挑选 public void select() { int k, i, selectId; float ran1; // Random random = new Random(System.currentTimeMillis()); for (k = 1; k < scale; k++) { ran1 = (float) (random.nextInt(65535) % 1000 / 1000.0); // System.out.println("概率"+ran1); // 产生方式 for (i = 0; i < scale; i++) { if (ran1 <= Pi[i]) { break; } } selectId = i; // System.out.println("选中" + selectId); copyGh(k, selectId);} } //进化函数,正常交叉变异 public void evolution() { int k; // 挑选某代种群中适应度最高的个体 selectBestGh(); // 赌轮选择策略挑选scale-1个下一代个体 select(); // Random random = new Random(System.currentTimeMillis()); float r; // 交叉方法 for (k = 0; k < scale; k = k + 2) { r = random.nextFloat();// /产生概率 // System.out.println("交叉率..." + r); if (r < Pc) { // System.out.println(k + "与" + k + 1 + "进行交叉..."); //OXCross(k, k + 1);// 进行交叉 OXCross1(k, k + 1); } else { r = random.nextFloat();// /产生概率 // System.out.println("变异率1..." + r); // 变异 if (r < Pm) { // System.out.println(k + "变异..."); OnCVariation(k); } r = random.nextFloat();// /产生概率 // System.out.println("变异率2..." + r); // 变异 if (r < Pm) { // System.out.println(k + 1 + "变异..."); OnCVariation(k + 1); } } } } //进化函数,保留最好染色体不进行交叉变异 public void evolution1() { int k; // 挑选某代种群中适应度最高的个体 selectBestGh(); // 赌轮选择策略挑选scale-1个下一代个体 select(); // Random random = new Random(System.currentTimeMillis()); float r; for (k = 1; k + 1 < scale / 2; k = k + 2) { r = random.nextFloat();// /产生概率 if (r < Pc) { //OXCross1(k, k + 1);// 进行交叉 OXCross(k,k+1);//进行交叉 } else { r = random.nextFloat();// /产生概率 // 变异 if (r < Pm) { OnCVariation(k); } r = random.nextFloat();// /产生概率 // 变异 if (r < Pm) { OnCVariation(k + 1); } } } if (k == scale / 2 - 1)// 剩最后一个染色体没有交叉L-1 { r = random.nextFloat();// /产生概率 if (r < Pm) { OnCVariation(k); } } } // 类OX交叉算子 void OXCross(int k1, int k2) { int i, j, k, flag; int ran1, ran2, temp; int[] Gh1 = new int[cityNum]; int[] Gh2 = new int[cityNum]; // Random random = new Random(System.currentTimeMillis()); ran1 = random.nextInt(65535) % cityNum; ran2 = random.nextInt(65535) % cityNum; // System.out.println(); // System.out.println("-----------------------"); // System.out.println("----"+ran1+"----"+ran2); while (ran1 == ran2) { ran2 = random.nextInt(65535) % cityNum; } if (ran1 > ran2)// 确保ran1<ran2 { temp = ran1; ran1 = ran2; ran2 = temp; } // System.out.println(); // System.out.println("-----------------------"); // System.out.println("----"+ran1+"----"+ran2); // System.out.println("-----------------------"); // System.out.println(); flag = ran2 - ran1 + 1;// 删除重复基因前染色体长度 for (i = 0, j = ran1; i < flag; i++, j++) { Gh1[i] = newPopulation[k2][j]; Gh2[i] = newPopulation[k1][j]; } // 已近赋值i=ran2-ran1个基因 for (k = 0, j = flag; j < cityNum;)// 染色体长度 { Gh1[j] = newPopulation[k1][k++]; for (i = 0; i < flag; i++) { if (Gh1[i] == Gh1[j]) { break; } } if (i == flag) { j++; } } for (k = 0, j = flag; j < cityNum;)// 染色体长度 { Gh2[j] = newPopulation[k2][k++]; for (i = 0; i < flag; i++) { if (Gh2[i] == Gh2[j]) { break; } } if (i == flag) { j++; } } for (i = 0; i < cityNum; i++) { newPopulation[k1][i] = Gh1[i];// 交叉完毕放回种群 newPopulation[k2][i] = Gh2[i];// 交叉完毕放回种群 } // System.out.println("进行交叉--------------------------"); // System.out.println(k1+"交叉后..."); // for (i = 0; i < cityNum; i++) { // System.out.print(newPopulation[k1][i] + "-"); // } // System.out.println(); // System.out.println(k2+"交叉后..."); // for (i = 0; i < cityNum; i++) { // System.out.print(newPopulation[k2][i] + "-"); // } // System.out.println(); // System.out.println("交叉完毕--------------------------"); } // 交叉算子,相同染色体交叉产生不同子代染色体 public void OXCross1(int k1, int k2) { int i, j, k, flag; int ran1, ran2, temp; int[] Gh1 = new int[cityNum]; int[] Gh2 = new int[cityNum]; // Random random = new Random(System.currentTimeMillis()); ran1 = random.nextInt(65535) % cityNum; ran2 = random.nextInt(65535) % cityNum; while (ran1 == ran2) { ran2 = random.nextInt(65535) % cityNum; } if (ran1 > ran2)// 确保ran1<ran2 { temp = ran1; ran1 = ran2; ran2 = temp; } // 将染色体1中的第三部分移到染色体2的首部 for (i = 0, j = ran2; j < cityNum; i++, j++) { Gh2[i] = newPopulation[k1][j]; } flag = i;// 染色体2原基因开始位置 for (k = 0, j = flag; j < cityNum;)// 染色体长度 { Gh2[j] = newPopulation[k2][k++]; for (i = 0; i < flag; i++) { if (Gh2[i] == Gh2[j]) { break; } } if (i == flag) { j++; } } flag = ran1; for (k = 0, j = 0; k < cityNum;)// 染色体长度 { Gh1[j] = newPopulation[k1][k++]; for (i = 0; i < flag; i++) { if (newPopulation[k2][i] == Gh1[j]) { break; } } if (i == flag) { j++; } } flag = cityNum - ran1; for (i = 0, j = flag; j < cityNum; j++, i++) { Gh1[j] = newPopulation[k2][i]; } for (i = 0; i < cityNum; i++) { newPopulation[k1][i] = Gh1[i];// 交叉完毕放回种群 newPopulation[k2][i] = Gh2[i];// 交叉完毕放回种群 } } // 多次对换变异算子 public void OnCVariation(int k) { int ran1, ran2, temp; int count;// 对换次数 // Random random = new Random(System.currentTimeMillis()); count = random.nextInt(65535) % cityNum; for (int i = 0; i < count; i++) { ran1 = random.nextInt(65535) % cityNum; ran2 = random.nextInt(65535) % cityNum; while (ran1 == ran2) { ran2 = random.nextInt(65535) % cityNum; } temp = newPopulation[k][ran1]; newPopulation[k][ran1] = newPopulation[k][ran2]; newPopulation[k][ran2] = temp; } /* * for(i=0;i<L;i++) { printf("%d ",newGroup[k][i]); } printf("\n"); */ } public void solve() { int i; int k; // 初始化种群 initGroup(); // 计算初始化种群适应度,Fitness[max] for (k = 0; k < scale; k++) { fitness[k] = evaluate(oldPopulation[k]); //适应度即路径长度// if(oldPopulation[k][0] == start|| oldPopulation[k][7] == end)// fitness[k] = -1;// System.out.println(fitness[k]); } // 计算初始化种群中各个个体的累积概率,Pi[max] countRate(); System.out.println("初始种群..."); for (k = 0; k < scale; k++) { for (i = 0; i < cityNum; i++) { System.out.print(oldPopulation[k][i] + ","); } System.out.println(); System.out.println("----" + fitness[k] + " " + Pi[k]); } for (t = 0; t < MAX_GEN; t++) { //evolution(); evolution1(); // 将新种群newGroup复制到旧种群oldGroup中,准备下一代进化 for (k = 0; k < scale; k++) { for (i = 0; i < cityNum; i++) { oldPopulation[k][i] = newPopulation[k][i]; } } // 计算种群适应度 for (k = 0; k < scale; k++) { fitness[k] = evaluate(oldPopulation[k]); // if(oldPopulation[k][0] == start || oldPopulation[k][7] == end)// fitness[k] =-1;} // 计算种群中各个个体的累积概率 countRate(); } System.out.println("最后种群..."); for (k = 0; k < scale; k++) { for (i = 0; i < cityNum; i++) { System.out.print(oldPopulation[k][i] + ","); } System.out.println(); System.out.println("---" + fitness[k] + " " + Pi[k]); } System.out.println("最佳长度出现代数:"); System.out.println(bestT); System.out.println("最佳长度"); System.out.println(bestLength); System.out.println("最佳路径:"); for (i = 0; i < cityNum; i++) { System.out.print(bestTour[i] + ","); } } /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { System.out.println("Start...."); GA ga = new GA(30, 8, 2000, 0.8f, 0.9f); ga.init("c://data.txt"); ga.solve(); } }
2、TSP变式
如果出发点和终点固定,假设城市0位起点,城市7为终点,可将该路线图想象为有向图,所有城市均不能到达城市0,城市7不能不到达所有城市(都设为无穷大),经过迭代后即可求出答案
距离矩阵
private int[][] distance =
{{0, 300, 360, 210, 590, 475 , 500, 690},
{10000, 0 ,380, 270, 230, 285, 200, 390},
{10000, 380, 0 ,510 ,230, 765, 580, 770},
{10000, 270 , 510, 0, 470, 265, 450, 640},
{10000, 230, 230, 470 ,0, 515 , 260, 450},
{10000, 285, 765, 265, 515, 0 ,460, 650},
{10000, 200 , 580 , 450 ,260 ,460 ,0 ,190},
{10000, 10000 ,10000, 10000 ,10000, 10000 ,10000, 0}}; // 距离矩阵 */
其余代码同上
3.有约束条件的遗传算法
TSP问题没有其他的约束条件,但对于求解一个多元函数,可能要求
0<x<100,y >x等等,这时候就需要考虑约束条件。
我看过几篇论文,关于这个问题有修复不可行解法,改变遗传算子法,惩罚函数法,我没有深入研究过。不过我做过一个题,是多约束条件的,用了罚函数来体现违反约束的程度,并对适应度进行相应惩罚,也得出了结果。
罚函数是通过对不可行解的惩罚将约束问题转化为无约束问题,任何对约束的违法都要在目标函数中添加惩罚项。这个未完待续……
暂时掌握,后期更新。若文章有误,还请指正,谢谢!
2019年7月16日 周二
遗传算法求解TSP及其变式相关推荐
- 局部搜索、模拟退火和遗传算法求解TSP问题
模拟退火和遗传算法求解TSP问题 源代码传送门:GITHUB 数据传送门:TSPLIB 文章目录 模拟退火和遗传算法求解TSP问题 摘要 1 导言 1.1 问题重述 1.2 TSP问题选择 1.3 思 ...
- 人工智能导论——遗传算法求解TSP问题实验
一.实验目的: 熟悉和掌握遗传算法的原理.流程和编码策略,并利用遗传算法求解组合优化问题,理解求解TSP问题的流程并测试主要参数对结果的影响. 二.实验原理: 旅行商问题,即TSP问题(Traveli ...
- 【建模算法】基于遗传算法求解TSP问题(matlab求解)
[建模算法]基于遗传算法求解TSP问题(matlab求解) TSP (traveling salesman problem,旅行商问题)是典型的NP完全问题,即其最坏情况下的时间复杂度随着问题规模的增 ...
- 基于遗传算法求解TSP问题(旅游路径规划,Python实现,超详细,可视化,结果分析)
ps:作者是很用心写的,如果觉得不错,请给作者一点鼓励噢!(点赞收藏评论噢) 基于遗传算法求解TSP问题 摘要 巡回旅行商问题(TSP)是组合优化中的经典问题.常见的TSP问题求解算法例如穷举法.贪心 ...
- 【老生谈算法】matlab实现遗传算法求解TSP问题——TSP问题
遗传算法求解TSP问题MATLAB实现 1.文档下载: 本算法已经整理成文档如下,有需要的朋友可以点击进行下载 序号 文档(点击下载) 本项目文档 [老生谈算法]遗传算法求解TSP问题MATLAB实现 ...
- 【运筹优化】GA遗传算法求解TSP问题(Java实现)
文章目录 代码 Genome基因类 GeneticAlgorithm_TSP遗传算法类 运行结果 代码 Genome基因类 import lombok.Data; import lombok.NoAr ...
- 【Matlab】 遗传算法求解TSP问题
[Matlab] 遗传算法求解TSP问题 文章目录 [Matlab] 遗传算法求解TSP问题 前言 一.问题描述 二.实验设计 1.问题案例 2.读入数据 3.适应度计算 4. 选择子代 5. 结果输 ...
- 基于遗传算法求解TSP问题(JAVA)
一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...
- 【人工智能导论】遗传算法求解TSP问题(含源码github)
源程序:Github链接 Symmetric traveling salesman problem (TSP) Given a set of n nodes and distances for eac ...
- 遗传算法求解TSP问题(python版)
简介 改进和实现遗传算法,用以对旅行商问题(TSP问题)进行建模和近似求解,从而深入对启发式算法的理解. 算法流程 遗传算法解决TSP的流程是以下几部分:初始化种群.计算适应度函数.选择.交叉.变异然 ...
最新文章
- 解决Debian-7.1下Chrome浏览器字体难看的问题
- centos下为firefox安装flash插件的几种方法
- android自带蓝牙例子详解
- 方格路径问题!【转】
- C语言 pthread_join
- websocket包解析
- 不宜使用Selenium自动化的10个测试场景
- 吉大c 语言程序设计奥鹏作业,吉大18秋学期《C语言程序设计》在线作业一答案...
- 高级人才、专业技术人才、技能人才 目录 1. 高级人才,	1 1.1. 专业技术人才	2 2. 专业技术人才	2 3. 高技能人才 	3 1.高级人才, 可迁入本市市区落户,其配偶、未婚子女(含离
- dbeaver 修改数据_GitHub 上 5 款超好用的数据库 GUI 带你玩转 MongoDB、Redis、SQL 数据库...
- python编写性别比例失衡_性别比例失衡加剧什么情况?什么原因导致这样的结果?...
- OpenGL 编程指南(第八版)学习笔记——1 OpenGL概述
- html将图片转为圆形并居中
- 第三周项目4 穷举法
- Java和C专项练习
- WordPress相关二次开发教程篇,简单易学
- 债券基础知识和可转债剖析
- Pascal VOC数据集 下载 百度云
- LTSPICE调用下载的lib文件步骤
- vue 微信登录(前后台详细教程)
热门文章
- efucms搭建教程_EFUCMS E16小说漫画系统源码 最新完美UI设计漫画/听书直播源码程序...
- 【Code】浅谈Pascal转C++
- 信息资源管理——基础
- 数据仓库与数据挖掘的个人总结
- python学习之生成器
- 《软件工程导论》考研复习
- 数据库课程设计——人才市场管理系统、教学管理系统、产品销售管理系统、小区物业管理系统
- bp神经网络模型的优缺点,bp神经网络缺点及克服
- java ssm旅游网站系统源码jsp maven项目推荐
- 发电厂计算机监控课,那比水利发电厂监控系统课件.ppt