a算法TSP旅行商java_A*算法实现旅行商问题(人工智能报告,付代码)

一、

问题描述

“旅行商问题”常被称为“旅行推销员问题”,是指一名推销员要拜访多个地点时,如何找到在拜访每个地点一次后再回到起点的最短路径。规则虽然简单,但在地点数目增多后求解却极为复杂。

旅行商问题在本实验中的具体化:从A城市出发,到达每个城市并且一个城市只允许访问一次,最后又回到原来的城市,寻找一条最短距离的路径。

二、

知识表示

1、A*算法概述

A* 算法是N.Nillson于1971年提出的一种有序搜索算法, 该算法被认为是求解人工智能问题的最成功的技术理论之一。

Nillson指出对于某一已到达的现行状态, 如已到达图中的n节点,

它是否可能成为最佳路径上的一点的估价,

应由估价函数f(n)值来决定。

假设g*(n)函数值表示从起始节点s 到任意一个节点n 的一条最佳路径上的实际耗散值。h*(n)函数值表示从任意节点n 到目标节点ti

的最佳路径的实际耗散值。其中ti

是一个可能的目标节点。f*(n)函数值表示从起始s,通过某一指定的n 到达目标节点ti的一条最佳路径的实际耗散值,并有f*(n)=g*(n)+h*(n)。

假设f 函数是对f* 函数的一种估计, 并有f(n)=g(n)+h(n),其中g 函数是对g*

的估计,h 函数是对h* 的一种估计。f( n) 包括两个部分,其中g(n)表示到达n

节点时,已付出代价的估计;而h(n)表示从n

节点到达目标节点ti

将要付出代价的估计。

按f(n)=g*(n)+h*(n)的值来排序OPEN 表的节点,f 值小者优先。通常称这种算法为A算法。在A

算法的基础上,进一步限制h(n)函数,使得搜索图中的每一个节点n,能满足h(n)<=h*(n)、称h 函数取h* 的下界。这种算法叫A* 算法。

2、A*算法的状态

所谓状态,

是指在一定的时空范围内,问题所涉及的人、物、时间等的布局关系。通常把问题的初始布局关系称为初始状态,问题解决时到达的状态叫目标状态。这两个状态之间存在差异,如何从初始状态到达目标状态就是对问题求解。在状态空间法中问题的求解通常是从初始状态到达目标状态的一条最佳路径,这条路径依靠搜索算法在状态空间中寻找,这就是状态空间法的核心所在。

在旅行商问题中,初始状态就是旅行商在A城市准备出发送货,目标状态就是旅行商将所有的货送出归来到A城市。状态空间就是旅行商可以走的所有路径,本实验的解就是最短距离的路径。

3、估计函数的意义

对于某一已到达的现行状态, 假设现在的现行状态是从A走到C(一共五个城市,需走过B、C、D、E),那么下面可以走B、D、E,如果继续走B就表示为A->C->B,那么在OPEN表里,即可选定活路径就有六种选择:(1)A->C->B’;(2)A->C->D’; (3)A->C->E’;

(4)A->B;(5)A->D;(6)A->E。为什么有的是B、B’?在这里B的层数是2层,就是第二步走的是B;而B’的层数是3层,就是第三步走的是B。在OPEN表了的一个节点代表一条路径,而非简单的代表一个城市结点,所以在里面你会看到不同B的表现形式。对OPEN里的每一个节点做评估函数F分为两部分G和H:

G = 未走的城市数×目前的最小距离;

未走的的城市数=(总城市数+1)-目前城市的层数。为什得加1,因为最后得走回初始城市,所以总路径的城市数为总城市数+1。

假设从A城市走到X城市,又走到Y城市,所以H可表示为:

H = A到X的距离 +

X到Y的距离;

F = G + H ;

计算OPEN表里每个节点的F值,F值最小的节点作为活路径,从OPEN表中删除,放到CLOSE表里。

三、

算法实现

1、

数据结构

typedef struct _node {

int f;

//f值

int g;

//g值

int h;

//h值

int level;

//第几次走到这个点(important)

int parent;

//父城市;

int city;

//city num;

} node;

使用node结构体表述每一个城市。

typedef struct _list {

struct _list *next;

struct _list *pre;

struct _list *parent; //父城市节点指针

node city_node;

} nodelist, *nodeptr;

使用nodelist, *nodeptr描述路径,城市结点与城市结点的关系。

typedef struct _ttable {

struct _ttable *_this;

//this 指针

nodelist open;

//open表,

nodelist close;

//close表,(仓库)

//一些操作

nodeptr(*add_to_open)

(int);

nodeptr(*find_least_f)

(void);

void (*move_to_close) (nodeptr ptr);

void (*print_path) (nodeptr ptr);

} ttable;

Ttable相当一个总表,相当于面向对象的一个类,成员变量有OPEN表和CLOSE表,成员函数有nodeptr(*add_to_open) (int)、nodeptr(*find_least_f) (void)、void

(*move_to_close) (nodeptr ptr)、void

(*print_path) (nodeptr ptr)。

2、

程序流程

(1)读取输入的城市距离的临界矩阵。

(2)构造ttable,初始化,调用ttable

*table_constructor()函数,申请空间,将OPEN、CLOSE表设为NULL;

(3)默认第一个城市A放到OPEN表,将A城市标识设为-1,表示在当前最短路径里,A的层数设为1,A的F,H,G值初始化为0,更新最优路径临时指针指向A节点。

(4)OPEN表F值最小的节点作为新的最优节点城市。搜索与最优节点相邻且不在当前最短路径里的城市放到OPEN表,并将其父指针指向最优节点,把此时的最优节点城市放到CLOSE表里。

(5)判断最优路径临时指针是否指向前最优路径节点,如果不同,将最优路径临时指针指向当前最优节点,并撤销旧的最优路径,根据新的最优临时指针新建最优路径。

(6)循环第四部,直到最优路径上的节点数为城市数+1。

(7)输出最短路径,析构ttable。

四、

实验结果分析

(1)

a4c26d1e5885305701be709a3d33442f.png

(2)

a4c26d1e5885305701be709a3d33442f.png

(3)

a4c26d1e5885305701be709a3d33442f.png

经过多种测试,结果为最优解。

五、

程序清单

#include

#include

#include

#include

#define MAX_INT 99999999

typedef struct _node {

int f;

//f值

int g;

//g值

int h;

//h值

int level;

//第几次走到这个点(important)

int parent;

//父城市;

int city;

//city num;

}

node;

typedef struct _list {

struct _list *next;

struct _list *pre;

struct _list *parent;

//父城市节点指针

node city_node;

}

nodelist, *nodeptr;

nodeptr _add_to_open(int);

nodeptr _find_least_f();

void

_print_path(nodeptr ptr);

void

_move_to_close(nodeptr ptr);

nodeptr _remove_from_open(nodeptr ptr);

void

_add_to_close(nodeptr ptr);

typedef struct _ttable {

struct _ttable *_this;

//this 指针

nodelist open;

//open表,

nodelist close;

//close表,(仓库)

//一些的操作

nodeptr(*add_to_open)

(int);

nodeptr(*find_least_f)

(void);

void (*move_to_close) (nodeptr ptr);

void (*print_path) (nodeptr ptr);

}

ttable;

int

map[100][100];

int

b_path[100];

//best_path;

ttable *table = NULL;

ttable *table_constructor()

{//构造一个table实体

table = (ttable *) malloc(sizeof(ttable));

memset(table, 0, sizeof(ttable));

table->open.next = NULL;

table->close.next = NULL;

table->open.city_node.parent = -1;

table->open.city_node.city = -1;

table->close.city_node.parent = -1;

table->close.city_node.city = -1;

table->add_to_open = _add_to_open;

table->find_least_f = _find_least_f;

table->move_to_close = _move_to_close;

table->print_path = _print_path;

table->_this = table;

return table;

}

void

*table_destructor(ttable * table)

{//析构一个类

if (table != NULL) {

nodeptr p =

table->_this->open.next;

nodeptr q = NULL;

while (p) {

q = p->next;

free(p);

p = q;

}

p =

table->_this->close.next;

while (p) {

q = p->next;

free(p);

p = q;

}

free(table);

table = NULL;

}

}

nodeptr _add_to_open(int i)

{//添加到OPEN表

//放在第一个位置

nodeptr p = NULL;

p = (nodeptr) malloc(sizeof(nodelist));

memset(p, 0, sizeof(nodelist));

if (p == NULL) {

return p;

}

p->next = NULL;

p->parent = NULL;

p->city_node.parent = -1;

p->city_node.city = i;

p->city_node.level = 0;

p->city_node.f = 0;

p->city_node.g = 0;

p->city_node.h = 0;

p->next =

table->_this->open.next;

p->pre =

&table->_this->open;

if (table->_this->open.next)

{

table->_this->open.next->pre

= p;

}

table->_this->open.next =

p;

return p;

}

void

_add_to_close(nodeptr ptr)

{//添加到close表

ptr->next =

table->_this->close.next;

ptr->pre =

&table->_this->close;

if (table->_this->close.next)

{

table->_this->close.next->pre

= ptr;

}

table->_this->close.next =

ptr;

}

nodeptr _remove_from_open(nodeptr ptr)

{//从OPEN表中移除,不删除

ptr->pre->next =

ptr->next;

if (ptr->next)

ptr->next->pre =

ptr->pre;

return ptr;

}

nodeptr _find_least_f()

{//在OPEN表中找出最小的F节点

int least = MAX_INT;

nodeptr p, q = NULL;

p =

table->_this->open.next;

q = p;

while (p) {

if (p->city_node.f < least)

{

q = p;

least = p->city_node.f;

}

p = p->next;

}

return q;

}

void

_move_to_close(nodeptr ptr)

{//从OPEN移到CLOSE

_remove_from_open(ptr);

_add_to_close(ptr);

}

void

_print_path(nodeptr ptr)

{//打印路径

int least;

if (ptr == NULL)

return;

least = ptr->city_node.f;

printf("the best path is :");

printf("A ");

ptr = ptr->parent;

while (ptr) {

printf("%c ", ptr->city_node.city + 65);

ptr = ptr->parent;

}

printf("\nthe shortest length is %d\n", least);

}

int

main()

{

int num, min = MAX_INT;

int i, j, k, count;

int tmpf, tmph, tmpg;

ttable *table = (ttable *) table_constructor();

// 构造

nodeptr ptr = NULL, ptr_p = NULL, ptr_c = NULL;

nodeptr l_ptr = NULL; //the pointer of last best path;

//input city

do {

printf("请输入城市节点个数:2=

scanf("%d", &num);

} while (num >= 99 || num <=

1);

printf("\

请输入节点之间的距离矩阵:\n");

for (i = 0; i < num; i++) {

for (j = 0; j < num; j++) {

scanf("%d", &map[i][j]);

if (i != j && min >

map[i][j]) {

min = map[i][j];

}

}

}

//最后回到A

map[num][num] = map[0][0];

for (i = 0; i < num; i++) {

map[num][i] = map[0][i];

map[i][num] = map[i][0];

}

table->add_to_open(0);

while (1) {

ptr_p = table->find_least_f();

//'当前'最好节点,从最好节点回退肯定是最好路径

table->move_to_close(ptr_p);

//move to close table and save it;

if (l_ptr && l_ptr != ptr_p) {

//更新最好路径

while (l_ptr != NULL) {

b_path[l_ptr->city_node.city] = 0;

l_ptr = l_ptr->parent;

}

l_ptr = ptr_p;

while (l_ptr != NULL) {

b_path[l_ptr->city_node.city] = 1;

l_ptr = l_ptr->parent;

}

}

l_ptr = ptr_p;

for (i = 0, count = 0; i <= num; i++) {

if (b_path[i])

count++;

}

if (count == num + 1) {

//all city in best path,A in twice:First And Last.

break;

}

if (count == num) {

//left one,which ? Last A.Because we have never changed the value

of b_path[num].

ptr_c = table->add_to_open(num); //把它添加进开启列表中

ptr_c->city_node.parent =

ptr_p->city_node.city;

//把当前作为这的父节点

ptr_c->city_node.level =

ptr_p->city_node.level + 1; //他是父节点的下一层。

ptr_c->parent = ptr_p;

ptr_c->city_node.g =

ptr_p->city_node.g +

map[num][ptr_p->city_node.city];

//g

ptr_c->city_node.h = min * (num -

ptr_c->city_node.level);

//h

ptr_c->city_node.f =

ptr_c->city_node.g +

ptr_c->city_node.h;

//f

} else {

for (i = 0; i < num; i++) {

//对邻近的路径计算

if (i != ptr_p->city_node.city

&& map[i][j] != -1 ) {

if (!b_path[i]) {

//如果它不在'最短路径'中

ptr_c = table->add_to_open(i);

//把它添加进开启列表中

ptr_c->city_node.parent =

ptr_p->city_node.city;

//把当前作为这的父节点

ptr_c->city_node.level =

ptr_p->city_node.level + 1; //他是父节点的下一层。

ptr_c->parent = ptr_p;

ptr_c->city_node.g =

ptr_p->city_node.g +

map[i][ptr_p->city_node.city];

//g

ptr_c->city_node.h = min * (num -

ptr_c->city_node.level);

//h

ptr_c->city_node.f =

ptr_c->city_node.g +

ptr_c->city_node.h;

//f

}

}

}

}

}

table->print_path(l_ptr);

table_destructor(table);

return 0;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/475212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows phone 7 中文天气预报应用--来源http://www.cnblogs.com/liulunet/archive/2011/08/17/2141696.html...

windows phone 7 中文天气预报应用wp7的应用还是太少了&#xff0c;中文应用更少。虽然有天气预报应用但是自己感觉并不好用&#xff0c;感觉这样的程序应该很简单&#xff0c;于是萌生了自己写一个的想法。 印证了群里朋友说的一句话&#xff1a;程序员往往都是使用别人的程序…

LeetCode 666. 路径和 IV(树的遍历)

文章目录1. 题目2. 解题1. 题目 对于一棵深度小于 5 的树&#xff0c;可以用一组三位十进制整数来表示。 对于每个整数&#xff1a; 百位上的数字表示这个节点的深度 D&#xff0c;1 < D < 4。十位上的数字表示这个节点在当前层所在的位置 P&#xff0c; 1 < P <…

Prim最小生成树算法

在一个具有几个顶点的连通图G中&#xff0c;如果存在子图G包含G中所有顶点和一部分边&#xff0c;且不形成回路&#xff0c;则称G为图G的生成树&#xff0c;代价最小生成树则称为最小生成树。 许多应用问题都是一个求无向连通图的最小生成树问题。例如&#xff1a;要…

LeetCode 1214. 查找两棵二叉搜索树之和(二叉树迭代器+双指针)

文章目录1. 题目2. 解题1. 题目 给出两棵二叉搜索树&#xff0c;请你从两棵树中各找出一个节点&#xff0c;使得这两个节点的值之和等于目标值 Target。 如果可以找到返回 True&#xff0c;否则返回 False。 示例 1&#xff1a; 输入&#xff1a;root1 [2,1,4], root2 [1,…

LeetCode 323. 无向图中连通分量的数目(并查集)

文章目录1. 题目2. 解题1. 题目 给定编号从 0 到 n-1 的 n 个节点和一个无向边列表&#xff08;每条边都是一对节点&#xff09;&#xff0c;请编写一个函数来计算无向图中连通分量的数目。 示例 1: 输入: n 5 和 edges [[0, 1], [1, 2], [3, 4]]0 3| |1…

LeetCode 1120. 子树的最大平均值(DFS自底向上)

文章目录1. 题目2. 解题1. 题目 给你一棵二叉树的根节点 root&#xff0c;找出这棵树的 每一棵 子树的 平均值 中的 最大 值。 子树是树中的任意节点和它的所有后代构成的集合。 树的平均值是树中节点值的总和除以节点数。 示例&#xff1a;输入&#xff1a;[5,6,1] 输出&a…

LeetCode 1100. 长度为 K 的无重复字符子串(滑动窗口)

文章目录1. 题目2. 解题1. 题目 给你一个字符串 S&#xff0c;找出所有长度为 K 且不含重复字符的子串&#xff0c;请你返回全部满足要求的子串的 数目。 示例 1&#xff1a; 输入&#xff1a;S "havefunonleetcode", K 5 输出&#xff1a;6 解释&#xff1a; 这…

java点击按钮结线程_多线程的Java应用程序在调试工具Netbeans中单击“停止”按钮时输出一个奇怪的结果...

我使用wait()和notify()机制学习了java中的多线程。但我很好奇输出一个简单的多线程Java应用程序。代码如下&#xff1a;class Q {int n;boolean valueSet false;synchronized int get() {if (!valueSet) {try {wait();} catch (InterruptedException e) {System.out.println(…

LeetCode 544. 输出比赛匹配对(NBA季后赛对阵图)

文章目录1. 题目2. 解题1. 题目 在 NBA 季后赛中&#xff0c;我们总是安排较强的队伍对战较弱的队伍&#xff0c;例如用排名第 1 的队伍和第 n 的队伍对决&#xff0c;这是一个可以让比赛更加有趣的好策略。 现在&#xff0c;给你 n 支队伍&#xff0c;你需要以字符串格式输出…

LeetCode 1428. 至少有一个 1 的最左端列(二分查找)

文章目录1. 题目2. 解题2.1 二分查找2.2 直接走阶梯1. 题目 &#xff08;这是一个交互题&#xff09; 我们称只包含元素 0 或 1 的矩阵为二进制矩阵。 矩阵中每个单独的行都按非递减顺序排序。 给定一个这样的二进制矩阵&#xff0c;返回至少包含一个 1 的最左端列的索引&am…

LeetCode 370. 区间加法(差分思想)

文章目录1. 题目2. 解题1. 题目 假设你有一个长度为 n 的数组&#xff0c;初始情况下所有的数字均为 0&#xff0c;你将会被给出 k​​​​​​​ 个更新的操作。 其中&#xff0c;每个操作会被表示为一个三元组&#xff1a;[startIndex, endIndex, inc]&#xff0c;你需要将…

LeetCode 1256. 加密数字(bitset)

文章目录1. 题目2. 解题1. 题目 给你一个非负整数 num &#xff0c;返回它的「加密字符串」。 加密的过程是把一个整数用某个未知函数进行转化&#xff0c;你需要从下表推测出该转化函数&#xff1a; 示例 1&#xff1a; 输入&#xff1a;num 23 输出&#xff1a;"10…

java执行程序默认多线程吗_Java多线程 执行程序(1)

本文由作者收集整理所得&#xff0c;作者不保证内容的正确行&#xff0c;转载请标明出处。作者&#xff1a;关新全Java多线程执行程序(1)1.1Thread类static Thread.currentThread返回当前正在执行的线程对象的引用。join 等待线程终止。yield 暂停当前正在执行的线程对象&#…

LeetCode 531. 孤独像素 I

文章目录1. 题目2. 解题1. 题目 给定一幅黑白像素组成的图像, 计算黑色孤独像素的数量。 图像由一个由‘B’和‘W’组成二维字符数组表示, ‘B’和‘W’分别代表黑色像素和白色像素。 黑色孤独像素指的是在同一行和同一列不存在其他黑色像素的黑色像素。 示例: 输入: [[W,…

LeetCode 533. 孤独像素 II

文章目录1. 题目2. 解题1. 题目 给定一幅由黑色像素和白色像素组成的图像&#xff0c; 与一个正整数N, 找到位于某行 R 和某列 C 中且符合下列规则的黑色像素的数量: 行R 和列C都恰好包括N个黑色像素。列C中所有黑色像素所在的行必须和行R完全相同。 图像由一个由‘B’和‘W…

Windows 8桌面的尴尬

刚出炉的Windows8可谓荣宠极致&#xff0c;此时却被指出存在问题&#xff0c;面临失宠的尴尬。到底是什么问题呢&#xff1f; Windows 8中新的用户界面&#xff0c;已被完全证明是两级分化日益严重。  混合操作系统是一个新的GUI概念&#xff0c;友好地触摸界面接口&#xff…

LeetCode 1101. 彼此熟识的最早时间(排序+并查集)

文章目录1. 题目2. 解题1. 题目 在一个社交圈子当中&#xff0c;有 N 个人。每个人都有一个从 0 到 N-1 唯一的 id 编号。 我们有一份日志列表 logs&#xff0c;其中每条记录都包含一个非负整数的时间戳&#xff0c;以及分属两个人的不同 id&#xff0c;logs[i] [timestamp,…

【转载】世界各地对BI的应用状况

欧美企业对商务智能的应用 商务智能活动在美国和欧洲比在世界上任何其他地区都要发达&#xff0c;商务智能已经由“旁门左道”转变为“主门正道”。欧美的企业已经认识到商务智能的重要意义&#xff0c;因而对它寄予很高的期望&#xff0c;希望能够通过商务智能充分利用企业以往…

php gearman 扩展,Ubuntu 12.04 安装 gearman 以及php扩展安装脚本

#!/usr/bash#create by lhb#date 2014-05-07#desc install gearman and php extension for Ubuntu 12.04.4 LTS PHP 5.5apt-get update#安装依赖库apt-get install libboost-all-dev gperf libevent1-dev libcloog-ppl0mkdir -pv /home/lhb/software && cd /home/lhb/s…

LeetCode 379. 电话目录管理系统(哈希set)

文章目录1. 题目2. 解题1. 题目 设计一个电话目录管理系统&#xff0c;让它支持以下功能&#xff1a; get: 分配给用户一个未被使用的电话号码&#xff0c;获取失败请返回 -1check: 检查指定的电话号码是否被使用release: 释放掉一个电话号码&#xff0c;使其能够重新被分配 …