求解TSP问题

作业二:Hopfield、GA、ACO求解TSP问题

一、问题描述

TSP问题(Traveling Salesman Problem,旅行商问题),由威廉哈密顿爵士和英国数学家克克曼T.P.Kirkman于19世纪初提出。问题描述如下:

有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路已保证其旅行的费用最少?

为了简化问题,在本题中,假设所有城市都位于一个平面直角坐标系中,用(x , y)表示城市的坐标。本题随机生成了20个城市,他们的名称和位置如下:

城市信息

二、问题分析

TSP问题实质是找出一条最短的哈密尔顿回路,这是一类NPC问题。传统的算法贪心、DP等要么找不到最优解,要么时间空间开销太大,而启发式搜索算法可以在能够接受的时间内找到一个近似最优解。本实验分别通过Hopfield网络、GA算法、PSO粒子群算法这三种不同的启发式搜索算法解决TSP问题,求得最短路径。

三、运行环境

操作系统:Windows 10

工具环境:Python 3.5, tensorflow框架, matplotlib

四、Hopfield网络解TSP问题

1.算法描述

Hopfield神经网络是一种递归神经网络,由约翰·霍普菲尔德在1982年发明。Hopfield网络是一种结合存储系统和二元系统的神经网络。它保证了向局部极小的收敛,但收敛到错误的局部极小值(local minimum),而非全局极小(global minimum)的情况也可能发生。Hopfield网络也提供了模拟人类记忆的模型。

1.1 Hopfield网络的能量函数:

有输入:

E=-\frac{1}{2} \sum_{i=0}^n\sum_{j=0}^n \omega _{ij}   s_{i} s_{j}-\sum_{i=1}^nI_{i}s_{i}

没有输入:

E=-\frac{1}{2} \sum_{i=0}^n\sum_{j=0}^n\omega _{ij}s_{i}s_{j}=-\frac{1}{2} S^T\omega S

1.2 吸引子Attractor

网络的一个稳定的状态,设计一个与系统对应的能量函数,如果存在一个系统使得对任何初始状态,能量函数都随时间连续下降,那么系统是稳定的。

1.3 利用Hopfield求解问题的一般方法

第一步:分析问题,得到求解问题的目标方程,将目标方程变为能量方程的形式。

第二步:优化网络,目标是使网络能量减小到吸引子Attractor状态

采用异步的变化,每次选择一个神经元改变状态,当网络能量减小时就接受这种状态改变,不断改变直到网络的能量趋于稳定,网络达到稳定状态。

2.问题表述

求解TSP旅行商问题相当于求解一个约束优化问题

第一步:将问题表示为图,图中的每个点代表城市,如果两个城市可达则有边相连

第二步:将问题转换为Hopfield网络的结构:用矩阵表示

矩阵示例

矩阵含义:元素x_{ij} 表示第j时刻经过第i个城市

约束:

① 每行只有一个神经元的状态为1

② 每列只有一个神经元的状态为1

③ 所有的激活的神经元的个数之和等于城市总数

第三步:采用拉格朗日构造能量方程

① 拉格朗日法构造目标函数

Goal=\frac{A}{2}\sum_{i=1}^n \sum_{x=1}^n \sum_{j=1}^n s_{xi}d_{xy}(s_{y,i-1}+s_{y,i+1} )

C_{1} =\frac{B}{2}\sum_{x=1}^n \sum_{i=1}^n \sum_{j=1}^ns_{xi}s_{xj}    ,表示每行只有一个神经元的状态为1

C_{2}=\frac{C}{2}\sum_{i=1}^n \sum_{x=1}^n \sum_{j=1}^ns_{xi}s_{yi}     ,表示每列只有一个神经元的状态为1

C_{3}=\frac{D}{2}{(\sum_{x=1}^n \sum_{i=1}^ns_{xi}-n  )}^2   ,表示所有的激活的神经元的个数之和等于城市总数

E=Goal+C_{1} +C_{2} +C_{3}

② 将目标方程转换为Hopfield网络能量函数的形式,确定权重W和输入I

标准形式为:

E=-\frac{1}{2} \sum_{i=0}^n\sum_{j=0}^n \omega _{ij}   s_{i} s_{j}-\sum_{i=1}^nI_{i}s_{i}

将目标方程转化为上述形式得到:

E=-\frac{1}{2}\sum_{x=1}^n \sum_{i=1}^n \sum_{y=1}^n \sum_{j=1}^n s_{xi}\omega _{xi,yj}s_{yj}-\frac{1}{2}\sum_{x=1}^n \sum_{i=1}^nI_{xi}s_{xi}

权重W:

\omega _{xi,yj}=-Ad_{xy}(\delta _{i,j+1} +\delta _{i,j-1} )-B\delta _{xy}(1-\delta _{xy})-C\delta_{ij}(1-\delta_{xy}) -D(1-\delta_{ij})(1-\delta_{xy})

输入I:

I_{xi}=Dn

其中,

\delta_{xy}=1,x=y ,\delta_{xy}=0,x\neq y

④ 由于上述能量方程E的形式比较复杂可以进行进一步优化,减少权值参数的个数,得到:

E=\frac{B}{2}\sum_{x=1}^n(\sum_{i=1}^n s_{xi}-1 )^2+\frac{B}{2}\sum_{i=1}^n(\sum_{x=1}^n s_{yi}-1)^2+\frac{A}{2}\sum_{x=1}^n \sum_{y=1}^n \sum_{i=1}^n s_{xi}d_{xy}s_{y,i+1}

其对应的状态的增量的表达式为

\frac{du_{xi} }{t}=-\frac{dE}{dv_{xi}}=-B(\sum_{i=1}^nv_{xi}-1 )-B(\sum_{y=1}^nv_{yi}-1)-D\sum_{y=1}^n d_{xy}v_{y,i+1}

3.算法流程

第一步:初始化Hopfield神经完了过的的权值A、D

第二步:计算城市之间的距离,形成距离矩阵D_{xy}

第三步:初始化神经网络的输入状态U_{0},为城市时刻矩阵赋初值

U_{xi}(t)=\frac{1}{2}U_{0}ln(n-1)+\delta _{xy} ,\delta _{xy}\in {0,1}

第四步:计算状态的增量

\Delta U=\frac{du_{xi} }{t}=-\frac{dE}{ds_{xi}}=-B(\sum_{i=1}^ns_{xi}-1 )-B(\sum_{y=1}^ns_{yi}-1)-D\sum_{y=1}^n d_{xy}s_{y,i+1}

第五步:更新下一刻的输入状态

U_{xi}(t+1)=U_{xi}(t)+\frac{dU_{xi}}{dt}\Delta  t

第五步:更新下一刻输出状态S,并计算当前的能量E

S_{xi}(t)=\frac{1}{2}[1+tanh(\frac{U_{xi}(t)}{U_{0}})]

E=\frac{B}{2}\sum_{x=1}^n(\sum_{i=1}^n s_{xi}-1 )^2+\frac{B}{2}\sum_{i=1}^n(\sum_{x=1}^n s_{yi}-1)^2+\frac{A}{2}\sum_{x=1}^n \sum_{y=1}^n \sum_{i=1}^n s_{xi}d_{xy}s_{y,i+1}

第六步:检查当前的输出状态S,是否满足约束

重复上述过程,直到达到最大迭代次数。

4.运行结果及分析

Hopfield结果

由于Hopfield网络在能量下降的过程中采用了贪心的策略,因此也容易收敛到局部最优解。

五、GA算法解TSP问题

1.算法描述

遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。

遗传算法是从代表问题可能潜在的解集的一个种群开始的,而一个种群则由经过基因编码的一定数目的个体组成。

第一步:需要实现从表现型到基因型的映射即编码工作。

第二步:根据基因编码规则产生初代种群

第三步:初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代演化产生出越来越好的近似解。在每一代,根据个体的适应度大小选择个体,并借助于自然遗传学的遗传算子进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。

不断重复第三步直到找到问题的最优解或者达到一定的迭代次数。

第四步:选择末代种群中的最优个体经过解码,将基因的表示形式转换为表现型,可以作为问题近似最优解。

2.GA关键问题

2.1基因型表示:由20个城市名称组成的符号串

对于TSP问题,我们想要求解的目标是:一条经过所有城市且每个城市仅路过依次的最短路径。因此在GA算法中,可以用20个不同城市的名称组成的符号串表示这条路径,符号串中城市的先后次序表示访问城市的顺序。

2.2父代选择:采用轮盘赌算法进行概率性的选择,适应度Fitness更高的个体被选择的概率更高

每一个个体被选择的概率为P_{a} =\frac{Fitness(a)}{\sum_{}^{} Fitness(i) } ,从当代种群中选择250个个体用来产生子代。

轮盘赌算法介绍

轮盘赌选择又称比例选择算子,基本思想是:每个个体被选中的概率与其适应度函数值大小成正比。

算法过程

(1) 在[0,1]内产生一个符合均匀分布的随机数R

(2)若R\leq Q_{1} ,则第一个个体被选中

(3)同理,若Q_{k-1} < R\leq Q_{k}  ,则第k个个体被选中

其中,Q_{k} =\sum_{j=1}^k P_{k}

2.3子代选择:确定性的选择,选择新一代生成的全部250个个体和父代选择得到的250个个体共同组成下一代种群

2.4遗传算子

2.4.1突变

突变率为0.02,如果个体将发生突变,则随机从个体的基因串中取出两个基因,交换两个基因的位置。

为了简化问题,以8个城市为例,突变过程如下:

突变前:1 3 5 6 4 7 0 2

突变后:1 2 5 6 4 7 0 3

2.5.1重组

从经过父代选择的个体中选择两个个体分别作为Parent1和Parent2,子代一半由Parent1构成,另一半由Parent2构成,过程如下:

第一步:随机从Parent1中截取一段长度为10个城市的连续符号串,放入子代Child中对应的位置。

第二步:遍历Parent2,将子代Child中不曾出现的城市按顺序放入空缺的位置。

为了简化问题,以8个城市为例,产生子代的重组过程如下:

Parent1: City0 City2 City4 City6 City7 City5 City3 City1

Parent2: City5 City3 City4 City6 City7 City2 City1 City0

第一步:随机从Parent1中截取City4 City6 City7 City5片段

此时,Child: None None City4 City6 City7 City5 None None

第二步:遍历Parent2,将子代Child中不曾出现的城市按顺序放入空缺的位置。

得到子代Child: City3 City2 City4 City6 City7 City5 City1 City0


2.5适应度评估 Fitness=\frac{1}{travelcost} =\frac{1}{routelength}

求解的目标是旅途费用最小的线路,也就是经过所有城市的最短路线,travelcost=routelength= \sum_{i=0}^{18}distance(i,i+1)

2.6停止迭代条件:连续20代结果不再产生变化

由于GA算法具有随机性,即便设置固定的迭代数也不能保证得到稳定的结果,所以选择以此作为停止迭代的条件,提升算法的稳定性。

3.算法流程

第一步:初始化基因

将城市名称和城市的位置信息(x , y)存入基因中,为了减少计算的时间,在初始化城市信息后计算任意两个城市之间的距离,并保存在表中。通过这种方式减少了大量对距离的计算,后续操作中只需查表即可得到距离。

第二步:生成个体,初始化种群

每个个体由20个各异的基因组成,通过对基因的随机排列组合得到由500个个体组成的初代种群。

第三步:种群演化

先进行父代选择,依据个体适应度进行概率性选择,选出250个个体。

从250个个体中选择两个分别作为Parent1和Parent2重组产生250个新的子代个体,对250个子代个体进行突变,突变率为0.02.

不断进行第三步直到连续20代结果不再产生变化。

第四步:输出末代适应度Fitness最高个体,并利用matplotlib展示结果

4.运行结果及分析

经过69次迭代,最短路径为1974.3720837875187

GA结果

分析:
4.1如何提高Exploitation能力

①通过适应度来进行父代选择,具有高适应度的个体可以产生子代

子代融合了两个父代的特点,可以视作是基于父代进行的局部搜索,选择具有高适应度的父代,提高了该个体附近的解被搜索的次数。

②进行突变

突变只会对个体中的两个基因的位置进行交换,保留了突变前个体的大部分路径,可以看作是在突变前个体附近进行局部搜索。

4.2 如何提高Exploration能力

① 进行概率性而非确定性的选择

让适应度比较低的个体也有被选择的机会,通过这种方式可以协助跳出局部最优值,增加全局搜索的能力。

在迭代的过程中观察到使用GA算法解TSP问题的时候,比较容易陷入局部最优解,如图10代到40代之间长期停留在局部最优解附近。结合上述关于exploitaion和exploraion的分析,可以得出导致这一现象的原因是因为选择时随机性不够,轮盘赌选择法虽然可以按照概率的比例进行选择,但是其结果会受到顺序的影响。为了进一步提升算法,可以使用锦标赛选择法或线性排序选择法代替轮盘赌选择法进行随机选择。

六、ACO算法解TSP问题

1.算法描述

1.1 蚁群算法Ant Colony Optimization, ACO

一种用来在图中寻找优化路径的机率型算法。其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。蚁群算法是一种群智能算法,与其他优化算法相比,蚁群算法具有以下几个特点:

(1)采用正反馈机制,使得搜索过程不断收敛,最终逼近最优解。

(2)每个个体可以通过释放信息素来改变周围的环境,且每个个体能够感知周围环境的实时变化,个体间通过环境进行间接地通讯。

(3)搜索过程采用分布式计算方式,多个个体同时进行并行计算,大大提高了算法的计算能力和运行效率。

(4)启发式的概率搜索方式不容易陷入局部最优,易于寻找到全局最优解。

1.2 基本原理

1、蚂蚁在路径上释放信息素。

2、碰到还没走过的路口,就随机挑选一条路走。同时,释放与路径长度有关的信息素。

3、信息素浓度与路径长度成反比。后来的蚂蚁再次碰到该路口时,就选择信息素浓度较高路径。

4、最优路径上的信息素浓度越来越大。

5、最终蚁群找到最优寻食路径。

2.问题表述

2.1 TSP问题表示

由于在上述TSP问题中,任意两个城市都是可达的,因此可以利用矩阵存储任意两城市之间的路径的相关信息。本算法涉及4个矩阵:

距离矩阵D:|City_num|*|City_num|,矩阵中的每一个元素d_{ij} 表示城市i与城市j之间路径的长度。

信息素矩阵P:|City_num|*|City_num|,矩阵中的每一个元素\tau _{ij} 表示城市i与城市j之间路径上的信息素浓度

期望矩阵E:|City_num|*|City_num|,矩阵中的每一个元素\eta _{ij} 表示城市i与城市j之间路径长度的倒数

路径矩阵Path:|Ant_num|*|City_num|,矩阵中的每一个元素Path_{ij} 表示蚂蚁 i 第 j 个访问的城市对应的序号。矩阵的每一行表示了一只蚂蚁访问所有城市的路径。

2.2 在TSP求解中,假设蚁群算法中的蚂蚁按照下方公式行动。

2.2.1 每一只蚂蚁依照概率选择从当前城市i移动到城市j

P_{ij}^k=\frac{\tau _{ij}^\alpha \eta _{ij}^\beta }{\sum\nolimits_{j\in \Lambda }^{}\tau _{ij}^\alpha \eta _{ij}^\beta}

k: 表示蚁群中的第k只蚂蚁

i:表示当前蚂蚁k所在城市

j:表示蚂蚁k要前往的下一个城市

\tau :城市i到城市j的路径上的信息素浓度

\eta :城市i到城市j的路径的期望,是距离的倒数

\alpha :信息素影响因子

\beta :期望影响因子

2.2.2 任意两城市之间路径上的信息素更新规律如下

 \tau _{ij} (n+1)=(1-\rho)\times \tau _{ij} (n)+\sum_{k=1}^m \Delta \tau _{ij}^k

\Delta \tau_{ij}^k=\frac{Q}{\sum\nolimits d_{ij} }  (如果蚂蚁k经过了城市i,j之间的路径)

\rho :信息素挥发率

Q:影响因子

d_{ij} :城市i,j之间路径的长度

2.3 解的形式

历史上的路径矩阵中路径长度最短的一行。

3.算法流程

3.1 初始化

第一步:读取城市坐标信息并计算任意两城市之间的距离,将结果存储到距离矩阵D中。

第二步:利用距离矩阵D求期望矩阵E,E中对角元素的取值为0,其中元素为距离矩阵D中元素的倒数。

第三步:初始化每条路径上信息素的浓度为1,即创建一个全为1的信息素矩阵P。

第四步:初始化每只蚂蚁的路径,因为所求解为哈密顿回路,因此蚂蚁的起点对结果不产生影响,为简化算法流程让每只蚂蚁都从第0个城市City1出发。

3.2 开始蚁群的迭代

对于蚁群中的每一只蚂蚁:

第一步:从第0个城市City1出发

第二步:依据选择下一个城市的概率公式,对每一个未达城市计算该城市为蚂蚁从当前位置出发的目的地的概率。再通过轮盘选择法(算法详情见前文)依据概率进行选择,概率大的城市被选中的概率高。

P_{ij}^k=\frac{\tau _{ij}^\alpha \eta _{ij}^\beta }{\sum\nolimits_{j\in \Lambda }^{}\tau _{ij}^\alpha \eta _{ij}^\beta}

第三步:当蚁群中所有蚂蚁的路径矩阵都填满,即每只蚂蚁都产生了一个解,计算每只蚂蚁本次路程的总长度。

第四步:迭代更新最短距离和最短路程的信息。

第五步:更新信息素矩阵

 \tau _{ij} (n+1)=(1-\rho)\times \tau _{ij} (n)+\sum_{k=1}^m \Delta \tau _{ij}^k  \Delta \tau_{ij}^k=\frac{Q}{\sum\nolimits d_{ij} }

重复上述过程iter_max次。

3.3 输出最短距离和最短路程

输出结果,并绘制图表:

① ACO算法计算过程中迭代次数和相应的最优解的关系图

② 绘制路径图。

4.运行结果及分析

第一次实验结果

最短距离为1881. 2414942503106

num_ant =200  # 蚂蚁个数

num_city =20  # 城市个数

alpha =1  # 信息素影响因子

beta =1  # 期望影响因子

info =0.1  # 信息素的挥发率

iter_max =50#最大迭代次数


ACO 迭代50次

第二次实验结果

num_ant =200  # 蚂蚁个数

num_city =20  # 城市个数

alpha =1  # 信息素影响因子

beta =1  # 期望影响因子

info =0.1  # 信息素的挥发率

iter_max =500#最大迭代次数

ACO 迭代500次

由两次结果对比可见,在城市数量为20的情况下,经过500次迭代得到的结果与50次结果相同。由ACO Convergence图可知,由于城市数量比较少,在迭代次数为50次时结果已经趋近于稳定。

同时可以观察到,与Hopfield算法和GA算法得到的结果相比,ACO算法有更好的exploration能力,在迭代的过程中并没有出现长期停留在某一局部最优解附近的现象。同时与前两种问题相比,ACO算法在迭代次数和最终结果上都表现得更为出色。

六、搜索问题的统一表述:状态空间(State Space)

1. 状态空间State Space=(S,F,C,I,G)

S:状态的集合

F:用于转换状态的函数的集合

C:转换消耗的集合,即每执行一次状态转换操作需要的消耗的集合

I:初始状态的集合

G:目标状态的集合

2. 用状态空间表示搜索问题

① 针对所求问题写出所有的状态,将初始状态和目标状态做好标记

② 将所有造成状态转换的操作用转换函数的形式表示

③ 将状态作为节点,以不同的转换函数作为边,构造相应的图

④ 求解的过程即为搜索图的过程,解的形式是:一条从初始状态到目标状态的路径

3. 搜索的方法:启发式搜索

复杂的问题对应的在状态空间下的图也更为复杂,对于这样的图很难使用传统的BFS和DFS进行穷举搜索,如果遍历所有的状态将花费巨大的计算资源和时间资源。为了进一步加快搜索的过程,可以采用启发式搜索,也就是有选择的选择扩展节点。

3.1 评估函数Evaluation Function

对于状态空间中的每个状态节点,可以给出一个评估函数f(n)=g(n)+h(n)

g(n):从初始状态节点到达当前所达状态节点n的所有消耗

h(n):从当前状态节点n到目标状态节点的消耗的估计值

f(n):从初始节点经过状态节点n到目标状态节点的总消耗

3.2 启发式搜索步骤

第一步:将初始状态节点放入Open table;

第二步:根据每个节点的评估函数从Open table选择一个节点扩展;

第三步:扩展选中节点,将扩展节点放入Open table,扩展完毕后,将被扩展节点放入Closed table;

重复二、三步,直到选中目标节点进行扩展或Open table为空。

4. 举例:TSP问题在状态空间下的表述

4.1 状态:对于n个城市的TSP问题,用含有n个元素的一维向量表示状态,含义是从1到n时刻经过的城市的顺序。

以8个城市的TSP问题为例:

初始时刻:None None None None None None None None

目标时刻:City0 City1 City2 City3 City4 City5 City6 City7 (假设这是消耗最小的游览顺序)

第3时刻的状态:City2 City3 City1 None None None None None

4.2 转移函数:从一个城市移动到另一个城市

距离:选择City5作为下一个城市对应的状态转换

第3时刻的状态:City2 City3 City1 None None None None None

第4时刻的装填:City2 City3 City1 City5 None None None None

4.3 评估函数:表示旅行的消耗

g(n)=当前所有实际走过的路程之和

h(n)= 距离当前最近的未达城市的距离 * 未达城市的个数 (满足可容许条件)

七、Exploitation和exploration问题

Exploitation:指在局部搜索的能力,在一个局部进行精密的搜索找到更优解

Exploration:指在全局搜索的能力,在全局范围内搜索避免陷入局部最优解。

易知,在计算能力有限的情况下,Exploitation和Exploration的平衡问题决定了近似最优解的质量。如果Exploitation过多,则会导致陷入局部最优解而无法找到全局最优解;如果exploration过多,虽然扩大了搜索范围,但在每个区域的搜索却过于粗糙,也会导致错过最优解。只有结合两种能力的优势,才能得到更好的近似最优解。

如何提升Exploitaion和exploration能力(在状态空间表述下)

4.1如何提高Exploitation能力

① 根据评估函数进行选择,评估函数值大的节点被选中进行扩展的概率高

因为该节点之后的所有节点的状态基于当前节点,是在当前节点的基础上进行进一步的操作,所以对于状态图来说,选择扩展节点的过程可以看作是在进行局部搜索。根据评估函数进行选择可以使得具有更好的评估函数值的节点及其之后的节点拥有更多被搜索的机会。

② 在局部上不断迭代寻找最优解

4.2 如何提高Exploration能力

① 在选择节点扩展时,进行概率性而非确定性的选择

让评估函数值比较低的节点也有被选择的机会,通过这种方式可以协助跳出局部最优值,增加全局搜索的能力。

② 对状态图进行剪枝

剪枝操作可以去除一些对求最优解无用的状态图分支,通过减少一些无用的局部搜索来提高搜索的效率,从而可以进行更多的全局搜索。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359