上篇我们用遗传算法求解了方程,其中用到的编码方式是二进制的编码,实现起来相对简单很多,

就连交配和变异等操作也是比较简单,但是对于TSP问题,就稍微复杂一点,需要有一定的策略,

才能较好的实现。

这次的TSP问题的题目是:

随机产生10~30个城市,每个城市之间的距离也是随机产生,距离的范围是[1,50],求最优的路径

==========================================================

下面就是具体的求解,由于我的策略是基于知网上的一种改进的遗传算法求解TSP问题》这篇文章,

所以把这篇文章先放上来。下面我简单介绍一下这篇文章关于求解TSP问题的策略,然后附上参照这篇

文章写的代码。

策略简述:

1、染色体编码

为了充分利用城市间相邻边的信息和距离的信息,不采用二进制编码而是采用整数编码,即每个染

色体都是一个1到N的排列,表示周游路线的城市间的先后顺序序列。

        /// <summary>
/// 初始化群体
/// </summary>
static void Initial_Group()
{
int count = ;//已产生个体数
List<int> myRoad = new List<int>();
string road = string.Empty;//个体的表现型
for (int i = ; i < city_count; i++)
{
myRoad.Add(i);
}
while (count < gruopCount)//20个个体
{
int tmp, index;
for (int i = ; i < myRoad.Count; i++)//随机交换得到一组路径(个体)
{
index = rd.Next(myRoad.Count);
tmp = myRoad[i];
myRoad[i] = myRoad[index];
myRoad[index] = tmp;
}
for (int i = ; i < myRoad.Count; i++)//将个体转化成路径存到种群中
{
road += MyEncode(myRoad[i]);//自己编码如果大于10,转化成对应的符号
}
group.Add(road);
count++;
road = "";
}
//foreach (var item in group)
//{
// Console.WriteLine(item + " " + Ca(item));
//}
}

2、选择算子

这里没有采用轮盘赌算法,而是采用了锦标赛选择,即每次从群体中随机抽 取出M个个体,然后选

择其中适应值最好的进入下 一代,接着进行下一个锦标赛选择直至选出种群数目个个体为止。锦标

赛选择算子保证了更优的染色体能够有更大的存活机会,当然,同一个优秀的个体被多次选中也是

允许的。这里的M取2.

        /// <summary>
/// 选择(锦标赛)
/// 思路:1.产生两个不同的随机数作为要参加锦标赛的两个个体;2.判断适应度大小,
/// 小的被选择(最短路径)
/// </summary>
/// <param name="list">适应度集合</param>
static void Selection(List<int> list)
{
int count = ;//选择的数量
List<string> result = new List<string>();//选择的结果
while (count < gruopCount)
{
int test1 = rd.Next(, gruopCount);//要参加锦标赛的的两个个体
int test2 = rd.Next(, gruopCount);
if (test1 != test2)
{
if (list[test1] >= list[test2])
{
result.Add(group[test2]);
}
else
{
result.Add(group[test1]);
}
}
count++;
}
//更新种群信息
for (int i = ; i < result.Count; i++)
{
group[i] = result[i];
}
}

3、交配算子

利用相邻边的信息和距离的信息作为启发来设计一种基于顶点的候选表的交配算子(CandidateCrossover)

具体步骤如下:

①交配算子根据交配概率pc来选择两个父体进行交配。把这两个父体看作是两个循环队列,然后产生一个

随机数k作为交配位。 交配位所对应的父体1中的城市作为当前的城市加入到子代1中;

②找到该城市在父体2中对应的位置,分别把该城市在父体1和 父体2中的左右邻接城市(和这个城市相连接

的边的另外两个城市)加入到当前城市的候选表中,如果其左右邻接城市已在子代中,则选择其次邻接城市,

依次类推直至所选取的城市不在子 代中,而最后一个城市的下一个城市是第一个城市;

③根据距离矩阵计算当前城市和候选表中的各个城市的距离,找出与当前城市距离最短的城市加入到子代中,

并且把这个距离最短的城市又当作当 前城市,找到此城市在父体1中的位置,返回到第2 步继续执行,

直到所有的城市加入到子代1中为止。

        /// <summary>
/// 基于邻接表的交叉实现
/// </summary>
/// <param name="str1">个体1的染色体</param>
/// <param name="str2">个体2的染色体</param>
/// <returns></returns>
static string Candidate_Crossover(string str1, string str2)
{
int k = rd.Next(city_count);
int j = ;
List<int> list = new List<int>();//子代
List<int> tmp = new List<int>();//候选表
string result = string.Empty;
string son = str1[k].ToString();//第一个个体选的城市
int current = MyDecode(son);//当前城市
list.Add(MyDecode(son));
while (list.Count < city_count)
{
if (list.Count < city_count - )
{
for (int i = ; i < str2.Length; i++)
{
if (MyDecode(str2[i].ToString()) == current)
{
j = i;
break;
}
}
string str = "";
//str1 左边
for (int i = ; i < str1.Length; i++)
{
str = str1[(k - i + city_count) % city_count].ToString();
if (!list.Contains(MyDecode(str)))
{
tmp.Add(MyDecode(str));
break;
}
}
//str1 右边
for (int i = ; i < str1.Length; i++)
{
str = str1[(k + i) % city_count].ToString();
if (!list.Contains(MyDecode(str)))
{
tmp.Add(MyDecode(str));
break;
}
}
//str2 左边
for (int i = ; i < str2.Length; i++)
{
str = str2[(j - i + city_count) % city_count].ToString();
if (!list.Contains(MyDecode(str)))
{
tmp.Add(MyDecode(str));
break;
}
}
//str2 右边
for (int i = ; i < str2.Length; i++)
{
str = str2[(j + i) % city_count].ToString();
if (!list.Contains(MyDecode(str)))
{
tmp.Add(MyDecode(str));
break;
}
}
Dictionary<int, int> dic = new Dictionary<int, int>();
foreach (var item in tmp)
{
if (!dic.ContainsKey(item))
{
dic.Add(item, distance[current, item]);
}
}
int minKey = dic.OrderBy(s => s.Value).Select(s => s.Key).FirstOrDefault();
for (int i = ; i < str1.Length; i++)
{
if (minKey == MyDecode(str1[i].ToString()))
{
k = i;
current = minKey;
list.Add(minKey);
break;
}
}
tmp.Clear();
}
else if (list.Count == city_count - )
{
foreach (var a in str1)
{
if (!list.Contains(MyDecode(a.ToString())))
{
list.Add(MyDecode(a.ToString()));
}
}
}
} foreach (var item in list)
{
result += MyEncode(item);
}
return result;
}

4、变异算子

变异操作发生在某个染色体的某个基因上,它将可变性引入群体中,增强了群体的多样性,从而提供了从局部

最优中跳出来的一种手段。变异方法也是一个随机的、盲目的变异,因此需要使用比较小的变异概率(pm)

来控制以避免造成种群的破坏。这里采用的是基于位置的变异也称为插入式变异(InsertionMutation),该算子

在染色体中随机产生两个变异位,然后把第二个位置的基因插入到第一个位置的基因之前。

         /// <summary>
/// 插入式变异(ISM)
/// 思路:1.产生两个随机位置;2.将第二个位置的数放在第一个位置的数的前面
/// </summary>
/// <param name="str1">要变异的个体</param>
/// <returns>变异过后的个体</returns>
static string Opreation_Mutation(string str1)
{
int pos1 = rd.Next(, city_count);//产生两个位置
int pos2 = rd.Next(, city_count);
if (pos1 < pos2)
{
string s = str1[pos2 - ].ToString();
return str1.Insert(pos1 - , s).Remove(pos2, );
}
else if (pos1 > pos2)
{
string s = str1[pos1 - ].ToString();
return str1.Insert(pos2 - , s).Remove(pos1, );
}
else//如果相等的两个位置,则重新产生小范围的随机数
{
int pos3 = rd.Next(, city_count / );
int pos4 = rd.Next(city_count / , city_count);
string s = str1[pos2 - ].ToString();
return str1.Insert(pos1 - , s).Remove(pos2, );
}
}

其中的方法,实现不唯一,时间比较敢,也没有作一定的优化,只是为了熟悉算法而写的。

希望能帮到初学者,也欢迎各位提出修改意见。

完整代码可在这下载

https://github.com/hwqdt/Catcher.TSP

遗传算法的简单应用-巡回旅行商(TSP)问题的求解的更多相关文章

  1. 二进制状态压缩dp(旅行商TSP)POJ3311

    http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Subm ...

  2. Hamilton回路 旅行商TSP问题 /// dp oj1964

    题目大意: 给出一个n个顶点的无向图,请寻找一条从顶点0出发,遍历其余顶点一次且仅一次.最后回到顶点0的回路——即Hamilton回路. Input 多测试用例.每个测试用例: 第一行,两个正整数 n ...

  3. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  4. ACM/ICPC 之 数据结构-邻接表+DP+队列+拓扑排序(TSH OJ-旅行商TSP)

    做这道题感觉异常激动,因为在下第一次接触拓扑排序啊= =,而且看了看解释,猛然发现此题可以用DP优化,然后一次A掉所有样例,整个人激动坏了,哇咔咔咔咔咔咔咔~ 咔咔~哎呀,笑岔了- -|| 旅行商(T ...

  5. 2016全国研究生数学建模A题多无人机协同任务规划——基于分布式协同多旅行商MTSP遗传算法

    MTSP问题是指:有Ⅳ个城市,要求旅行商到达每个城市各一次,且仅一次,并[旦 1到起点,且要求旅行路线最短.而多旅行商问题M个旅行商从同一个城市(或多个城市)出发.分羽走一条旅路线,且总路程缀短.有关 ...

  6. hdu 4281 Judges' response(多旅行商&DP)

    Judges' response Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  7. vijosP1014 旅行商简化版

    vijosP1014 旅行商简化版 链接:https://vijos.org/p/1014 [思路] 双线DP. 设ab,ab同时走.用d[i][j]表示ab所处结点i.j,且定义i>j,则有转 ...

  8. 洛谷P1782 旅行商的背包[多重背包]

    题目描述 小S坚信任何问题都可以在多项式时间内解决,于是他准备亲自去当一回旅行商.在出发之前,他购进了一些物品.这些物品共有n种,第i种体积为Vi,价值为Wi,共有Di件.他的背包体积是C.怎样装才能 ...

  9. Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”

    整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...

随机推荐

  1. 价值1400美元的CEH(道德黑客)认证培训课程长啥样?(3)工具集

    美元的CEH(道德黑客)认证培训课程长啥样?(3)工具集 这是我收到的CEH官方发来的邮件,参加CEH认证培训原价为1424.25刀,可以给我便宜到1282刀.只有一个感觉,心在流血.站在这价值120 ...

  2. Yii Model中添加默认搜索条件

    在查询中增加条件 public function defaultScope() { return array( 'condition' => " is_deleted = 0" ...

  3. 可拖动的DIV

    在做WEB UI设计的时候,拖动某个HTML元素已经成为一种不能忽视的用户界面模式,比较典型的应用例子就是Dialog,一个元素是怎么实现拖动的呢?其实原理非常简单,要想实现首先得了解几个基本知识. ...

  4. java 锁!

    问题:如何实现死锁. 关键: 1 两个线程ta.tb 2 两个对象a.b 3 ta拥有a的锁,同时在这个锁定的过程中,需要b的锁:tb拥有b的锁,同时在这个锁定的过程中,需要a的锁: 关键的实现难点是 ...

  5. [数据库连接池] Java数据库连接池--DBCP浅析.

    前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务 ...

  6. Atitit 判断判断一张图片是否包含另一张小图片

    Atitit 判断判断一张图片是否包含另一张小图片 1. keyword1 2.  模板匹配是在图像中寻找目标的方法之一(切割+图像相似度计算)1 3. 匹配效果2 4. 图片相似度的算法(感知哈希算 ...

  7. C#、.Net代码精简优化(空操作符(??)、as、string.IsNullOrEmpty() 、 string.IsNullOrWhiteSpace()、string.Equals()、System.IO.Path 的用法)

    一.空操作符(??)在程序中经常会遇到对字符串或是对象判断null的操作,如果为null则给空值或是一个指定的值.通常我们会这样来处理: .string name = value; if (name ...

  8. 领会CSS,实际中的研究

    虽懂却不会,真是可怕,自认懂却了无. 善用CSS属性选择器 在用于区别和唯一的情况下完全可以使用属性选择器,而没有必要使用class或id p[city="http://www.css.co ...

  9. WP中的语音识别(下):语音指令

    除了系统集成的可以用于搜索.启动应用程序等语音命令外,在我们的应用程序内部还能自己定义语音指令,使得我们的APP能与语音操控结合得更加完全. 语音指令是通过一个XML文件来定义的.比如,咱小舅子开了家 ...

  10. WPF自定义控件与样式(10)-进度控件ProcessBar自定义样

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Pro ...