【问题描述】
马的遍历问题。在8×8方格的棋盘上,从任意指定方格出发,为马寻找一条走遍棋盘每一格并且只经过一次的一条路径。
传统算法:
首先这是一个搜索问题,运用深度优先搜索进行求解。算法如下:
1、 输入初始位置坐标x,y;
2、 步骤 c:
如果c> 64输出一个解,返回上一步骤c--
(x,y) ← c
计算(x,y)的八个方位的子结点,选出那此可行的子结点
循环遍历所有可行子结点,步骤c++重复2
显然(2)是一个递归调用的过程,大致如下:
void dfs(int x,int y,int count)
{
int i,tx,ty;
if(count> N*N)
{
output_solution();//输入一个解
return;
}
for(I=0;i <8;++i)
{
tx=hn[i].x;//hn[]保存八个方位子结点
ty=hn[i].y;
s[tx][ty]=count;
dfs(tx,ty,count+1);//递归调用
s[tx][ty]=0;
}
}
这样做是完全可行的,它输入的是全部解,但是马遍历当8×8时解是非常之多的,用天文数字形容也不为过,这样一来求解的过程就非常慢,并且出一个解也非常慢。
怎么才能快速地得到部分解呢?
所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
贪心算法的基本思路如下:
1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
实现该算法的过程:
从问题的某一初始解出发;
while 能朝给定总目标前进一步 do
求出可行解的一个解元素;
由所有解元素组合成问题的一个可行解。
下面是一个可以试用贪心算法解的题目,贪心解的确不错,可惜不是最优解。
其实马踏棋盘的问题很早就有人提出,且早在1823年,J.C.Warnsdorff就提出了一个有名的算法。在每个结点对其子结点进行选取时,优先选择‘出口’最小的进行搜索,‘出口’的意思是在这些子结点中它们的可行子结点的个数,也就是‘孙子’结点越少的越优先跳,为什么要这样选取,这是一种局部调整最优的做法,如果优先选择出口多的子结点,那出口少的子结点就会越来越多,很可能出现‘死’结点(顾名思义就是没有出口又没有跳过的结点),这样对下面的搜索纯粹是徒劳,这样会浪费很多无用的时间,反过来如果每次都优先选择出口少的结点跳,那出口少的结点就会越来越少,这样跳成功的机会就更大一些。这种算法称为为贪心算法,也叫贪婪算法或启发示算法,它对整个求解过程的局部做最优调整,它只适用于求较优解或者部分解,而不能求最优解。这样的调整方法叫贪心策略,至于什么问题需要什么样的贪心策略是不确定的,具体问题具体分析。实验可以证明马遍历问题在运用到了上面的贪心策略之后求解速率有非常明显的提高,如果只要求出一个解甚至不用回溯就可以完成,因为在这个算法提出的时候世界上还没有计算机,这种方法完全可以用手工求出解来,其效率可想而知。
个人代码(仅供参考):
#if !defined(AFX_HORSE_H__7543DB1E_0FD1_438C_A261_5B8791E184F3__INCLUDED_)
#define AFX_HORSE_H__7543DB1E_0FD1_438C_A261_5B8791E184F3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class Horse
{
public:
void initArray();
void calcu();
Horse();
private:
int output[9][9];
int dushu[9][9];
};
#endif // !defined(AFX_HORSE_H__7543DB1E_0FD1_438C_A261_5B8791E184F3__INCLUDED_)
// Horse.cpp: implementation of the Horse class.
//
//////////////////////////////////////////////////////////////////////
#include<iostream>
#include<iomanip>
#include<stdlib.h>
#include "Horse.h"
using namespace std;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Horse::Horse()
{
int i,j;
for(i=1;i<=8;i++)
for(j=1;j<=8;j++)
output[i][j]='+';
cout<<endl;
for(i=1;i<=8;i++)
{
for(j=1;j<=8;j++)
cout<<setw(4)<<(char)output[i][j];
cout<<endl<<endl;
}
}
void Horse::calcu()
{
int x,y,m,n,i,j,z,k,min;
int walkway[9][3]={{0,0,0},{1,1,2},{2,1,-2},{3,-1,2},{4,-1,-2},{5,2,1},{6,2,-1},{7,-2,1},{8,-2,-1}};
printf("请输入起始坐标: x,y\n");
scanf("%d,%d",&m,&n);
if(m>=1&&m<=8&&n>=1&&n<=8)
{
for(z=1;z<=64;z++)
{
min = 8;
output[m][n]=z;
dushu[m][n]=0;
for(k=1;k<=8;k++)
{
x=m+walkway[k][1];
y=n+walkway[k][2];
if(x>=1&&x<=8&&y>=1&&y<=8)
if(dushu[x][y]!=0)
{
--dushu[x][y];
if(dushu[x][y]<min)
{
min=dushu[x][y];
i=x;
j=y;
}
}
}
m=i;n=j;
}
}
else
printf("输入错误!");
n=0;
struct information
{
int data;
int x;
int y;
}array[64];
for(i=1;i<=8;i++)
for(j=1;j<=8;j++)
{
array[n].data=output[i][j];
array[n].x=i;
array[n].y=j;
n++;
}
information temp[64];
for(i=0;i<63;i++)
{
for(j=0;j<63-i;j++)
if(array[j].data>array[j+1].data)
{
temp[j]=array[j];
array[j]=array[j+1];
array[j+1]=temp[j];
}
}
for(i=0;i<64;i++)
{
system("cls");
for(j=0;j<array[i].x;j++)
cout<<endl<<endl;
for(k=0;k<array[i].y;k++)
cout<<" ";
cout<<array[i].data;
_sleep(200);
system("cls");
}
for(i=1;i<=8;i++)
{
for(j=1;j<=8;j++)
cout<<setw(4)<<output[i][j];
cout<<endl<<endl;
}
}
void Horse::initArray()
{
int walkway[9][3]={{0,0,0},{1,1,2},{2,1,-2},{3,-1,2},{4,-1,-2},
{5,2,1},{6,2,-1},{7,-2,1},{8,-2,-1}};
int i,j,k,x,y;
for(i=1;i<=8;i++)
for(j=1;j<=8;j++)
dushu[i][j]=0;
for(i=1;i<=8;i++)
for(j=1;j<=8;j++)
for(k=1;k<=8;k++)
{
x=i;y=j;
x=x+walkway[k][1];
y=y+walkway[k][2];
if(x>=1&&x<=8&&y>=1&&y<=8)
dushu[i][j]++ ;
}
}
#include"Horse.h"
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
Horse horse;
horse.initArray();
horse.calcu();
return 0;
}