找了很多资料,终于查到了两份本人现在能看到比较明白的八数码(C++),TSP算法(matlab)代码,本来想连实验报告一起发的,后来想想算了,就发一下代码和自己理解写的注释,希望对校友有所帮助。
1.八数码
void move(int flag,Node *node)
{ //向四个方向扩展 ,flag用1表示右,2表示下,3表示左,4表示上
int temp;
if(flag==1&&node->x>0)
{ //靠右边,向左移动
Node *n = new Node();
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
n->a[i][j]=node->a[i][j]; //n接收node矩阵
}
}
n->a[node->x][node->y]=node->a[node->x-1][node->y]; //左移
n->a[node->x-1][node->y]=0; //对应位置置0,即置空
n->x=node->x-1; //改变x的值
n->y=node->y; //改变y的值
n->flag=3; //左边
n->father=node; //设node为n的父节点
n->g=node->g+1; // 求 g(),步骤加一,所以g只需+1
n->h=a_start_h(n); //求n节点的h
n->f=n->g+n->h; //f=g+h
open_cnt++; //扩展的节点
open_node_cnt++; //节点个数
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
} //以下三种情况同理,注释简略
else if(flag==2&&node->y<2)
{ //靠下,上移
Node *n = new Node();
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x][node->y+1]; //下移
n->a[node->x][node->y+1]=0;
n->x=node->x;
n->y=node->y+1;
n->flag=4;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
else if(flag==3&&node->x<2)
{ //靠左边,向右移
Node *n = new Node();
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x+1][node->y]; //右移
n->a[node->x+1][node->y]=0;
n->x=node->x+1;
n->y=node->y;
n->flag=1;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
else if(flag==4&&node->y>0)
{ //靠上,下移
Node *n = new Node();
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x][node->y-1];
n->a[node->x][node->y-1]=0;
n->x=node->x;
n->y=node->y-1;
n->flag=2;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
}
void expand(Node *node)
{ //节点扩展
for(int i=1;i<=4;i++)
{ //向4个方向扩展
if(i!=node->flag)
move(i,node);
}
}
int main()
{
input();
open[0].np = &start; //start放入open表
open_node_cnt=1; //从开始状态
if(isable()) //判断是否有解
{
while(true)
{ //open表不为空
if(isend(open[0].np)) //当找到目标节点时,输出
{
printf("\n路径:\n");
show(open[0].np);
break;
}
expand(open[0].np); //扩展最优节点的子节点
open[0].np=NULL;
open[0].f=-1;
open_node_cnt--; //open表数量-1
sort(open); //open表排序
}
}
else cout<<"无解";
system("pause");
}
Asuanfa
int a_h(Node *node)
{ //求 h()计算当前节点与目标节点相比数码不同的位置个数
int old_x,old_y,end_x,end_y;
int h=0;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(node->a[i][j]!=end.a[i][j]) //对应位置不同时
{
h++;
}
}
}
return h;
2.TSP
%%
function GaTSP
City_Num = 10; % 城市数目,可以任意数字,这里取10
[distant, location] = tsp(City_Num); % disstat为城市之间相互的距离,location为各城市的坐标
n = 10; %n为初始种群大小,随意设置大小
gn_Max = 600; % 最大代数,可改变
cross_Prob = 0.9; % 交叉概率,可改变 probably简记prob
mut_Prob = 0.2; % 变异概率,可改变 mutate
% 随机产生初始种群
pn = zeros(n, City_Num); % population 为初始种群,包括多条染色体 population简记pn
for i = 1 : n
pn(i,:) = randperm(City_Num); %randperm函数是返回1到n随机打乱得到的一个数字序列
end
[~, cumulativeProbs] = calPopulationValue(pn, distant); % 计算种群每条染色体的累计概率 cumulativeProbs
gn_Num = 1; %第一代 generation简记gn
gn_MeanValue = zeros(gn_Num, 1); % 每一代的平均距离
gn_MaxValue = zeros(gn_Num, 1); % 每一代的最短距离
best_Route = zeros(n, City_Num); % 最佳路径
new_Pn = zeros(n, City_Num); % 新的种群
while gn_Num <= gn_Max %当前代数未到达最大代数时,继续循环
for j = 1 : 2 : n %染色体两两交叉,所以步长为2
selected_Chromos = select(cumulativeProbs); % 选择操作,选出两条需要交叉编译的染色体,即父本母本
crossed_Chromos = cross(pn, selected_Chromos, cross_Prob); % 交叉操作,返回交叉后的染色体 染色体Chromosome
new_Pn(j, :) = mut(crossed_Chromos(1, :),mut_Prob); % 对交叉后的染色体进行变异操作
new_Pn(j + 1, :) = mut(crossed_Chromos(2, :), mut_Prob); % 对交叉后的染色体进行变异操作
end
pn = new_Pn; %产生了新的种群,进行换代
[populationValue, cumulativeProbs] = calPopulationValue(pn, distant); % 计算新种群的适应度
[fmax, nmax] = max(populationValue); % 记录当前代最好和平均的适应度
gn_MeanValue(gn_Num) = 1 / mean(populationValue); % 因为计算适应度时取距离的倒数,这里面取最大的倒数,即最短的距离
gn_MaxValue(gn_Num) = 1 / fmax;
bestChromo = pn(nmax, :); % 前代最佳染色体,即对应的路径
best_Route(gn_Num, :) = bestChromo; % 记录每一代的最佳染色体,也就是存储最佳线路
drawTSP(location, bestChromo, gn_MaxValue(gn_Num), gn_Num, 0); %绘图
gn_Num = gn_Num + 1; %代数加一
end
[bestValue,index] = min(gn_MaxValue);
drawTSP(location, best_Route(index, :), bestValue, index,1);
figure(2);
plot(gn_MaxValue, 'r');
hold on;
plot(gn_MeanValue, 'b');
grid;
title('搜索过程');
legend('最优解', '平均解');
fprintf('遗传算法得到的最短距离: %.2f\n', bestValue);
end
%
%------------------------------------------------
% 计算所有染色体的适应度
function [chromoValues, cumulativeProbs] = calPopulationValue(pn, distant)
n = size(pn, 1); % 读取种群大小10
chromoValues = zeros(n, 1); %chromoValues存储每条染色体适应度
for i = 1 : n
chromoValues(i) = CalDist(distant, pn(i, :)); % 计算每条染色体的适应度
end
chromoValues = 1./chromoValues'; % 因为距离越小,选取的概率越高,所以取距离倒数,语法./要注意,'转置
% 根据个体的适应度计算其被选择的概率
fsum = 0;
for i = 1 : n %计算分母fsum
% 乘以10次方的原因是让好的个体被选取的概率更大(因为适应度取距离的倒数,若不乘次方,则个体相互之间的适应度差别不大),换成一个较大的数也行
fsum = fsum + chromoValues(i)^10;
end
% 计算单个概率
probs = zeros(n, 1);
for i = 1: n
probs(i) = chromoValues(i)^10 / fsum;
end
% 计算累积概率
cumulativeProbs = zeros(n,1);
cumulativeProbs(1) = probs(1);
for i = 2 : n
cumulativeProbs(i) = cumulativeProbs(i - 1) + probs(i);
end
cumulativeProbs = cumulativeProbs'; %转置
end
%--------------------------------------------------
%“选择”操作,返回所选择染色体在种群中对应的位置
% cumulatedPro 所有染色体的累计概率
function selectedChromoNums = select(cumulatedPro)
selectedChromoNums = zeros(2, 1);
% 从种群中选择两个个体,最好不要两次选择同一个个体
for i = 1 : 2
r = rand; % 产生一个随机数
prand = cumulatedPro - r;
j = 1;
while prand(j) < 0
j = j + 1;
end
selectedChromoNums(i) = j; % 选中个体的序号
if i == 2 && j == selectedChromoNums(i - 1) % 若相同就再选一次
r = rand; % 产生一个随机数
prand = cumulatedPro - r;
j = 1;
while prand(j) < 0
j = j + 1;
end
end
end
end
%------------------------------------------------
% “交叉”操作
function crossedChromos = cross(population, selectedChromoNums, crossProb)
length = size(population, 2); % 染色体的长度
crossProbc = crossMuteOrNot(crossProb); %根据交叉概率决定是否进行交叉操作,1则是,0则否
crossedChromos(1,:) = population(selectedChromoNums(1), :); %把要交叉的染色体从种群中取出来
crossedChromos(2,:) = population(selectedChromoNums(2), :);
if crossProbc == 1
c1 = round(rand * (length - 2)) + 1; %在[1,bn - 1]范围内随机产生一个交叉位 c1 round函数用于舍入到最接近的整数
c2 = round(rand * (length - 2)) + 1; %在[1,bn - 1]范围内随机产生一个交叉位 c2
chb1 = min(c1, c2);
chb2 = max(c1,c2);
middle = crossedChromos(1,chb1+1:chb2); % 两条染色体 chb1 到 chb2 之间互换位置
crossedChromos(1,chb1 + 1 : chb2)= crossedChromos(2, chb1 + 1 : chb2);
crossedChromos(2,chb1 + 1 : chb2)= middle;
for i = 1 : chb1 % 看交叉后,染色体上是否有相同编码的情况(路径上重复出现两个城市)。若有,则该编码不参与交叉
while find(crossedChromos(1,chb1 + 1: chb2) == crossedChromos(1, i))
location = find(crossedChromos(1,chb1 + 1: chb2) == crossedChromos(1, i));
y = crossedChromos(2,chb1 + location);
crossedChromos(1, i) = y;
end
while find(crossedChromos(2,chb1 + 1 : chb2) == crossedChromos(2, i))
location = find(crossedChromos(2, chb1 + 1 : chb2) == crossedChromos(2, i));
y = crossedChromos(1, chb1 + location);
crossedChromos(2, i) = y;
end
end
for i = chb2 + 1 : length
while find(crossedChromos(1, 1 : chb2) == crossedChromos(1, i))
location = logical(crossedChromos(1, 1 : chb2) == crossedChromos(1, i));
y = crossedChromos(2, location);
crossedChromos(1, i) = y;
end
while find(crossedChromos(2, 1 : chb2) == crossedChromos(2, i))
location = logical(crossedChromos(2, 1 : chb2) == crossedChromos(2, i));
y = crossedChromos(1, location);
crossedChromos(2, i) = y;
end
end
end
end
%--------------------------------------------------
%“变异”操作
% choromo 为一条染色体
function snnew = mut(chromo,muteProb)
length = size(chromo, 2); % 染色体的的长度
snnew = chromo;
muteProbm = crossMuteOrNot(muteProb); % 根据变异概率决定是否进行变异操作,1则是,0则否
if muteProbm == 1
c1 = round(rand*(length - 2)) + 1; % 在 [1, bn - 1]范围内随机产生一个变异位
c2 = round(rand*(length - 2)) + 1; % 在 [1, bn - 1]范围内随机产生一个变异位
chb1 = min(c1, c2);
chb2 = max(c1, c2);
x = chromo(chb1 + 1 : chb2);
snnew(chb1 + 1 : chb2) = fliplr(x); % 变异,则将两个变异位置的染色体倒转 fliplr函数主要的作用是将矩阵进行左右翻转。
end
end
% 根据变异或交叉概率,返回一个 0 或 1 的数
function crossProbc = crossMuteOrNot(crossMuteProb)
test(1: 100) = 0;
l= round(100 * crossMuteProb);
test(1 : l) = 1;
n = round(rand * 99) + 1;
crossProbc = test(n);
end
%------------------------------------------------
% 计算一条染色体的适应度
% dislist 为所有城市相互之间的距离矩阵
% chromo 为一条染色体,即一条路径
function chromoValue = CalDist(distant, chromo)
Distant_sum = 0;
nlen = size(chromo, 2); % 染色体的长度
for i = 1 : (nlen - 1)
Distant_sum = Distant_sum + distant(chromo(i), chromo(i + 1));
end
Distant_sum = Distant_sum + distant(chromo(nlen), chromo(1)); %线路要闭合
chromoValue = Distant_sum;
end
%------------------------------------------------
% 画图
% Clist 为城市坐标
% route 为一条路径
function drawTSP(Clist, route, generationValue, generationNum,isBestGeneration)
CityNum = size(Clist, 1);
for i = 1 : CityNum - 1
plot([Clist(route(i), 1),Clist(route(i + 1), 1)], [Clist(route(i),2),Clist(route(i+1),2)],'ms-','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','g');
text(Clist(route(i), 1),Clist(route(i), 2), [' ', int2str(route(i))]);
text(Clist(route(i+1), 1),Clist(route(i + 1), 2), [' ', int2str(route(i+1))]);
hold on;
end
plot([Clist(route(CityNum), 1), Clist(route(1), 1)], [Clist(route(CityNum), 2), Clist(route(1), 2)],'ms-','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','g');
title([num2str(CityNum),'城市TSP']);
if isBestGeneration == 0
text(0, 0, ['第 ',int2str(generationNum),' 代',' 最短距离为 ', num2str(generationValue)]);
else
text(0, 0, ['最终搜索结果:最短距离 ',num2str(generationValue),', 在第 ', num2str(generationNum),' 代达到']);
end
hold off;
pause(0.005);
end
%------------------------------------------------
%城市位置坐标
function [DLn, cityn] = tsp(n)
DLn = zeros(n, n);
city10 = [0.444 0.4439;0.8439 0.1463;0.1707 0.2293;0.4293 0.761;0.5171 0.9414;
0.8732 0.6536;0.5878 0.5219;0.8488 0.3609;0.683 0.2536;0.6195 0.2634];
for i = 1 : 10
for j = 1 : 10
DLn(i, j) = ((city10(i,1)-city10(j,1))^2 + (city10(i,2)-city10(j,2))^2)^0.5;
end
end
cityn = city10;
end