您的位置:首页 > 其它

贪婪算法优化计算-马踏棋盘问题

2012-08-16 08:49 239 查看
一、    问题阐述

将马放到国际象棋的8*8棋盘board上的某个方格中,马按走棋规则进行移动,要求每个方格进入且只进入一次,走遍棋盘上的64个方格,将数字1,2,3…,64依次填入一个8*8的方阵,找出一种可行的方案,并用贪婪算法进行优化。

 



如图所示,当马在棋盘位置(4,3)时,它可以有1,2,3,4,5,6,7,8个位置可跳

二、    解题思路

1.    需求分析

棋盘可以看做一个矩阵,当马位于棋盘上某一位置时,它就有一个唯一的坐标,那么根据国际象棋的规则,它有8个位置可以跳,这8个位置的坐标是和当前马的坐标是有联系的,例如马的坐标是(x,y),那么它的下一跳的位置可以是(x-1,y-2)。当然坐标不能越界。马所在的当前位置标为1,它的下一跳的位置标为2,在下一跳的位置标为3,依次类推,如果马走完棋盘,那么最后在棋盘上标的位置是64。

2.      解决方案

(1)回溯法

我们可以采用回溯法求解,当马在当前位置时,我们将它下一跳的所有位置保存,然后从中选择一个位置作为当前位置在跳,递归下去,如果跳不下去,回溯。这有点类似图的深度搜索。

(2)贪婪法

贪婪算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。那么我们在回溯法的基础上,用贪婪算法进行优化,在选择下一跳的位置时,总是选择出口少的那个位置,这里出口少是指这个位置的下一跳位置个数少。这是一种局部调整最优的做法,如果优先选择出口多的子结点,那出口少的子结点就会越来越多,很可能出现‘死’结点,这样对下面的搜索纯粹是徒劳,这样会浪费很多无用的时间,反过来如果每次都优先选择出口少的结点跳,那出口少的结点就会越来越少,这样跳成功的机会就更大一些。

三、编写代码



#include<iostream>
#include<iomanip>
#include<fstream>
#include<vector>
#include<algorithm>
#include<cstdlib>
#include<ctime>
usingnamespacestd;

constintN=8;//棋盘规模
intoffsetX
={-1,1,-1,1,-2,-2,2,2};//相对于当前点马的下一落脚点x的偏移量
intoffsetY
={-2,-2,2,2,-1,1,-1,1};//相对于当前点马的下一落脚点y的偏移量
intchessboard

;//棋盘,此时每个chessboard[i][j]=0
//程序运行后要对chessboard[i][j]进行编号,从1,2,...,N*N

ofstreamlog;//输出文件流,记录贪婪寻优结果

classChessNode//马下一跳的位置--棋盘结点类
{
private:
intx;//此结点在棋盘的位置(x,y)
inty;
intwayout;//每个结点有8个出口,出口表示此结点的在棋盘下一跳的位置
//wayout表示此位置的出口数,如果在某一个方向没有出口,那么wayout=0

public:
ChessNode(int_x=0,int_y=0):x(_x),y(_y)
{
wayout=0;
}
intgetX()const
{
returnx;
}
intgetY()const
{
returny;
}
intgetwayout()const
{
returnwayout;
}
voidsetX(intX)
{
x=X;
}
voidsetY(intY)
{
y=Y;
}
boolIsCorrect()const
{
//此时要保证(x,y)不能越界并且此时chessboard[x][y]=0
//马才能跳到这一位置
if(x<N&&x>=0&&y<N&&y>=0&&chessboard[x][y]==0)
{
returntrue;
}
elsereturnfalse;
}
voidSetWayout()//设置结点的出口
{
intdirection;
for(direction=0;direction<N;direction++)//依次检测8个方向
{
intnx=x+offsetX[direction];//每一个方向的位置(nx,ny)
intny=y+offsetY[direction];
ChessNodenode(nx,ny);//构造一个结点位置
wayout+=node.IsCorrect();//求出出口数
}
}
voidshow()const
{
cout<<"("<<x<<","<<y<<")"<<endl;
cout<<wayout<<endl;
}
};

classLessThan//函数对象
{
public:
booloperator()(constChessNode&one,constChessNode&other)
{
returnone.getwayout()<other.getwayout();
}
};

constintmax=100000;//最大递归深度
classHourseJumpChessboard
{
private:
intRDepth;//递归的深度
intcount;//棋盘的编号
boolfind;

voidSuccess()//成功求解
{
inti,j;
log<<"程序运行后棋盘编号:"<<endl;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)log<<setw(4)<<chessboard[i][j]<<"";
log<<endl;
}
log<<"递归深度:"<<RDepth<<endl;
}

voidDFS(ChessNodenode,intcount)//普通的寻径算法,类似于图的深度遍历
{
//此时的算法很难得到正确的解,原因是程序在遍历时解空间太大
if(find==true||RDepth>max)
{
if(RDepth>max)
{
log<<"用普通寻径方式已经达到最大递归深度,无法得到正确的解!"<<endl;
}
return;//截断递归
}
if(count>N*N)
{
find=true;
Success();
}
intdirection;
for(direction=0;direction<N;direction++)//依次搜寻8个方向
{
ChessNodenode(node.getX()+offsetX[direction],node.getY()+offsetY[direction]);
if(node.IsCorrect())
{
RDepth++;
chessboard[node.getX()][node.getY()]=count;
DFS(node,count+1);
}
}
chessboard[node.getX()][node.getY()]=0;//此时node为死结点,即没有出口的结点
}

voidGreedyDFS(ChessNodenode,intcount)//用贪婪算法优化
{
if(find==true)return;//截断递归
if(count>N*N)
{
find=true;
Success();
}
intdirection;
vector<ChessNode>v;//保存下一跳位置结点
for(direction=0;direction<N;direction++)//依次搜寻8个方向
{
ChessNodenode(node.getX()+offsetX[direction],node.getY()+offsetY[direction]);
if(node.IsCorrect())
{
node.SetWayout();
v.push_back(node);
}
}
sort(v.begin(),v.end(),LessThan());//对向量v进行升序排序
vector<ChessNode>::iteratorit;
for(it=v.begin();it!=v.end();it++)
{
chessboard[it->getX()][it->getY()]=count;
RDepth++;
GreedyDFS(*it,count+1);
}
chessboard[node.getX()][node.getY()]=0;
}
public:
intgetRecursiveDepth()const
{
returnRDepth;
}
HourseJumpChessboard()
{
inti,j;
for(i=0;i<N;i++)//初始化棋盘
{
for(j=0;j<N;j++)chessboard[i][j]=0;
}
}

Walk(intx,inty)//初始位置(x,y)
{
ChessNodenode(x,y);
if(node.IsCorrect()==false)
{
cerr<<"初始位置不合法,程序退出!"<<endl;
exit(1);
}
find=true;
count=2;
RDepth=1;
chessboard[x][y]=1;
DFS(node,count);
}

GreedyWalk(intx,inty)//初始位置(x,y)
{
ChessNodenode(x,y);
if(node.IsCorrect()==false)
{
cerr<<"初始位置不合法,程序退出!"<<endl;
exit(1);
}
find=false;
count=2;
RDepth=1;
chessboard[x][y]=1;
GreedyDFS(node,count);
}
};

voidmain()
{
log.open("e:\\log.txt");
if(!log)
{
cerr<<"不能写日志文件,程序退出!"<<endl;
exit(1);
}
srand(unsigned(time(0)));
intn=28;//随机产生28个位置进行测试
inti;
intx,y;
for(i=0;i<n;i++)
{
HourseJumpChessboardhorse;
x=rand()%N;
y=rand()%N;
horse.Walk(x,y);//普通寻径方式

HourseJumpChessboardGreedyhorse;
Greedyhorse.GreedyWalk(x,y);//贪婪寻径方式
}
log.close();
}


 

四、测试

随机选取28个位置,用普通寻径算法和用贪婪法进行比较

从实验结果可以看出贪婪寻优起到了很大的作用

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 61   2  35  18  51   4  37  20

 34  17  62   3  36  19  52   5

  1  60  33  50  63  54  21  38

 16  49  56  59  32  47   6  53

 57  12  31  48  55  64  39  22

 30  15  58  43  40  25  46   7

 11  42  13  28   9  44  23  26

 14  29  10  41  24  27   8  45

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  5   8  23  38  57  10  25  28

 22  37   6   9  24  27  58  11

  7   4  39  56  45  60  29  26

 36  21  44  41  52  55  12  59

  3  40  51  46  61  42  53  30

 20  35  18  43  54  47  62  13

 17   2  33  50  15  64  31  48

 34  19  16   1  32  49  14  63

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 32  63  10   5  28  57  12   3

  9   6  31  64  11   4  27  58

 62  33   8  29  56  59   2  13

  7  30  61  42   1  52  55  26

 34  43  20  51  60  41  14  53

 19  50  35  44  47  54  25  40

 36  21  48  17  38  23  46  15

 49  18  37  22  45  16  39  24

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 44  25  42   7  48  23  60   5

 41   8  45  24  59   6  47  22

 26  43  52  49  46  57   4  61

  9  40  27  58  51  62  21  56

 28  53  50  39  34  55  64   3

 13  10  35  54  63  18  33  20

 36  29  12  15  38  31   2  17

 11  14  37  30   1  16  19  32

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  4   1   6  21  40  25  16  23

  7  20   3  46  17  22  39  26

  2   5  18  41  38  47  24  15

 19   8  63  50  45  42  27  48

 62  51  44  37  64  49  14  31

  9  36  61  58  43  30  55  28

 52  59  34  11  54  57  32  13

 35  10  53  60  33  12  29  56

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 11  16  49  32   9  18  21  60

 48  31  10  17  50  61   8  19

 15  12  47  52  33  20  59  22

 30  53  14  45  62  51  34   7

 13  46  29  54  35  58  23  64

 28  39  36   1  44  63   6  57

 37   2  41  26  55   4  43  24

 40  27  38   3  42  25  56   5

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 23  20   3  32  25  10   5   8

  2  33  24  21   4   7  26  11

 19  22   1  54  31  28   9   6

 34  53  60  29  44  51  12  27

 61  18  45  52  55  30  43  50

 38  35  62  59  46  49  56  13

 17  64  37  40  15  58  47  42

 36  39  16  63  48  41  14  57

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 33  22  31   8  35  12  41  10

 30   7  34  23  40   9  36  13

 21  32  39  44  37  60  11  42

  6  29  24  57  46  43  14  59

 25  20  45  38  61  58  55  50

  2   5  28  47  56  51  62  15

 19  26   3  52  17  64  49  54

  4   1  18  27  48  53  16  63

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  2  23   4  19  46  39  14  17

  5  20   1  40  15  18  51  38

 24   3  22  47  50  45  16  13

 21   6  63  44  41  48  37  52

 62  25  42  49  64  53  12  33

  7  28  61  58  43  34  55  36

 26  59  30   9  54  57  32  11

 29   8  27  60  31  10  35  56

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 13  36  15  46  11  34  29  56

 16  47  12  35  30  55  10  33

 37  14  45  48  51  32  57  28

 44  17  52  31  58  49  54   9

 21  38  43  50  53  60  27  64

 18  41  20  59  24  63   8   5

  1  22  39  42   3   6  61  26

 40  19   2  23  62  25   4   7

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 43  38  13  36  45  50  11  54

 14  35  44  51  12  55  46  49

 39  42  37  56  59  48  53  10

 34  15  64  41  52  17  58  47

 63  40  33  16  57  60   9  18

  4   1  30  61  32  21  26  23

 29  62   3   6  27  24  19   8

  2   5  28  31  20   7  22  25

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  2   5  28  23  18   7  30  33

 27  24   3   6  29  32  19   8

  4   1  26  55  22  17  34  31

 25  42  47  16  59  56   9  20

 46  15  58  41  54  21  60  35

 43  40  45  48  57  62  53  10

 14  49  38  63  12  51  36  61

 39  44  13  50  37  64  11  52

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  6  41   8  23   4  39  18  21

  9  24   5  40  19  22   3  38

 42   7  44  25  48  37  20  17

 33  10  57  36  45  26  49   2

 56  43  34  47  58   1  16  27

 11  32  55  62  35  46  59  50

 54  63  30  13  52  61  28  15

 31  12  53  64  29  14  51  60

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 16  31  12  41  26  29  10  59

 13  42  15  30  11  58  25  28

 32  17  40  43  54  27  60   9

 39  14  51  36  57  44  53  24

 18  33  38  55  52  61   8  45

  3  50  35  48  37  56  23  62

 34  19   2   5  64  21  46   7

  1   4  49  20  47   6  63  22

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  3   6  33  22  11   8  43  64

 34  21   4   7  44  63  12   9

  5   2  55  32  23  10  61  42

 54  35  20   1  62  45  24  13

 19  56  53  48  31  60  41  46

 36  49  30  57  52  47  14  25

 29  18  51  38  27  16  59  40

 50  37  28  17  58  39  26  15

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 14  11  38  33  16   1  20  23

 39  32  15  12  37  22  17   2

 10  13  40  55  34  19  24  21

 31  42  47  36  59  56   3  18

 46   9  58  41  54  35  60  25

 43  30  45  48  57  62  53   4

  8  49  28  63   6  51  26  61

 29  44   7  50  27  64   5  52

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 19  16  33  28  21   6   1   4

 32  29  20  17  34   3  22   7

 15  18  31  44  27  24   5   2

 30  43  62  25  54  35   8  23

 63  14  45  42  61  26  53  36

 46  41  64  55  52  49  60   9

 13  56  39  48  11  58  37  50

 40  47  12  57  38  51  10  59

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  8   5  10  25  32   3  20  23

 11  26   7   4  21  24  33   2

  6   9  28  31  60   1  22  19

 27  12  41  50  29  52  59  34

 40  49  30  61  42  57  18  53

 13  46  43  56  51  62  35  58

 44  39  48  15  64  37  54  17

 47  14  45  38  55  16  63  36

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  7  10  25  40  59  12  27  30

 24  39   8  11  26  29  60  13

  9   6  41  58  47  62  31  28

 38  23  46  43  54  57  14  61

  5  42  53  48  63  44  55  32

 22  37  20  45  56  49  64  15

 19   4  35  52  17   2  33  50

 36  21  18   3  34  51  16   1

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 14  29  10  41  24  27   8  45

 11  42  13  28   9  44  23  26

 30  15  52  43  40  25  46   7

 53  12  31  48  51  62  39  22

 16  49  54  61  32  47   6  63

  1  60  33  50  55  64  21  38

 34  17  58   3  36  19  56   5

 59   2  35  18  57   4  37  20

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  6  41   8  23   4  39  18  21

  9  24   5  40  19  22   3  38

 42   7  44  25  48  37  20  17

 33  10  57  36  45  26  49   2

 56  43  34  47  58   1  16  27

 11  32  55  62  35  46  59  50

 54  63  30  13  52  61  28  15

 31  12  53  64  29  14  51  60

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 11  52  13  54   9  60  23  56

 14  43  10  59  24  55   8  47

 51  12  53  44  61  48  57  22

 42  15  62  49  58  25  46   7

 37  50  41  30  45  64  21  26

 16  33  36  63  40  29   6   3

 35  38  31  18   1   4  27  20

 32  17  34  39  28  19   2   5

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  7   4   9  24  31   2  19  22

 10  25   6   3  20  23  32   1

  5   8  27  30  55  34  21  18

 26  11  56  35  28  51  60  33

 57  36  29  54  59  62  17  52

 12  39  58  45  42  53  50  61

 37  46  41  14  63  48  43  16

 40  13  38  47  44  15  64  49

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 23  20   1  16  33  38  11  14

  2  17  22  37  12  15  32  39

 21  24  19  34  43  40  13  10

 18   3  42  59  36  49  44  31

 25  58  35  50  41  60   9  48

  4  51  62  57  54  47  30  45

 63  26  53   6  61  28  55   8

 52   5  64  27  56   7  46  29

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

  1   4  35  20  47   6  43  22

 34  19   2   5  42  21  46   7

  3  36  41  48  39  54  23  44

 18  33  38  53  50  45   8  55

 37  14  49  40  61  56  51  24

 32  17  60  57  52  27  62   9

 13  58  15  30  11  64  25  28

 16  31  12  59  26  29  10  63

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 45   8  27  24  41  10  29  14

 26  23  44   9  28  13  42  11

  7  46  25  40  43  52  15  30

 22  39  48  51  60  31  12  53

 47   6  59  32  49  54  61  16

 38  21  50  55  58  33  64   1

  5  56  19  36   3  62  17  34

 20  37   4  57  18  35   2  63

递归深度:74

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 33  28   3  26  51  10   5   8

  2  25  32  61   4   7  50  11

 29  34  27  52  49  62   9   6

 24   1  64  31  60  47  12  41

 35  30  53  48  63  42  59  46

 20  23  18  43  54  57  40  13

 17  36  21  56  15  38  45  58

 22  19  16  37  44  55  14  39

递归深度:64

用普通寻径方式已经达到最大递归深度,无法得到正确的解!

程序运行后棋盘编号:

 19  16  33  28  21   6   1   4

 32  29  20  17  34   3  22   7

 15  18  31  44  27  24   5   2

 30  43  62  25  54  35   8  23

 63  14  45  42  61  26  53  36

 46  41  64  55  52  49  60   9

 13  56  39  48  11  58  37  50

 40  47  12  57  38  51  10  59

递归深度:64

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息