C++算法設(shè)計(jì)之馬踏棋盤(pán)的實(shí)現(xiàn)
本文實(shí)例為大家分享了C++算法設(shè)計(jì)之馬踏棋盤(pán)的具體代碼,供大家參考,具體內(nèi)容如下
(一)馬踏棋盤(pán)經(jīng)典算法描述:
(1)馬踏棋盤(pán)是經(jīng)典的程序設(shè)計(jì)問(wèn)題之一,主要的解決方案有兩種:一種是基于深度優(yōu)先搜索的方法,另一種是基于貪婪算法的方法。第一種基于深度優(yōu)先搜索的方法是比較常用的算法,深度優(yōu)先搜索算法也是數(shù)據(jù)結(jié)構(gòu)中的經(jīng)典算法之一,主要是采用遞歸的思想,一級(jí)一級(jí)的尋找,遍歷出所有的結(jié)果,最后找到合適的解。而基于貪婪的算法則是制定貪心準(zhǔn)則,一旦設(shè)定不能修改,他只關(guān)心局部最優(yōu)解,但不一定能得到最優(yōu)解。
【問(wèn)題描述】關(guān)于馬踏棋盤(pán)的基本過(guò)程:國(guó)際象棋的棋盤(pán)為 8*8 的方格棋盤(pán)?,F(xiàn)將"馬"放在任意指定的方格中,按照"馬"走棋的規(guī)則將"馬"進(jìn)行移動(dòng)。要求每個(gè)方格只能進(jìn)入一次,最終使得"馬"走遍棋盤(pán)的64個(gè)方格。
【算法分析】
① 在四角,馬踏日走只有兩個(gè)選擇;
② 在其余部分,馬踏日走有四、六、八不等的選擇。
解決方案:在外層另外加上兩層,確保 8*8 方格中的每一個(gè)格子都有8中不同的選擇;
重點(diǎn):為了確保每個(gè)格子能走日字,而且選擇的可能性等同,初始化除了最外兩層格子標(biāo)記沒(méi)有被訪問(wèn),最外兩層中每個(gè)格子都標(biāo)記為已被訪問(wèn)即可達(dá)到目標(biāo)!

解釋?zhuān)?/span>圖片中標(biāo)記紅色的區(qū)域,初始化時(shí)就默認(rèn)為馬已踏日字,集已被訪問(wèn),而中間的 8*8 的表格標(biāo)記為馬未被訪問(wèn)!
并且每一個(gè)表格中馬在訪問(wèn)時(shí)都有8中不同的選擇,這8中不同的選擇都會(huì)在其相應(yīng)的x和y坐標(biāo)上進(jìn)行追加標(biāo)記;
這8中選擇方式為:

【代碼展示1】:遞歸求解(回溯法求解),列出所有的解,并從中找出從(2,2)位置出發(fā)的合適解:
#include <iostream>
#include <stdlib.h>
?
using namespace std;
?
int chessboard[12][12] = {0};
?
int cnt = 0;?? ??? ??? ?//標(biāo)記馬已走的方格數(shù)
int sum = 0;?? ??? ??? ?//標(biāo)記馬走完全程的具體方案數(shù)
int move[8][2]={ {2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};?? ?//初始馬當(dāng)前位置向其周?chē)噜彴藗€(gè)日字的 x,y的偏移量
?
//輸出馬踏棋盤(pán)的解?
void PrintChess();
//馬踏棋盤(pán)遞歸過(guò)程
void Horse(int x,int y);?
?
int main(void){
?? ?int i,j;
?? ?for(i=0;i<12;i++){
?? ??? ?for(j=0;j<12;j++){
?? ??? ??? ?if(i==0 || i==1 || i==10 || i==11 || j==0 || j==1 || j==10 || j==11){
?? ??? ??? ??? ?chessboard[i][j]=-1;//在 8 * 8 的外層再加上兩層,確保 8 * 8 方格中的每一個(gè)格子都有 8 種不同的日字選擇?
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?//從起始位置開(kāi)始求得所有解
?? ?chessboard[2][2] = ++cnt;
?? ?Horse(2,2);?? ?//遞歸調(diào)用當(dāng)前當(dāng)前位置附近的 8 個(gè)日字,看看是否滿(mǎn)足條件
?? ?return 0;?
}?
?
void Horse(int x,int y){?? ??? ?//馬永遠(yuǎn)踏的是 x,y位置,而不是 a,b?
?? ?if(cnt >= 64){?? ??? ?//臨界值,馬走日字全部踏完,成功求出問(wèn)題解?? ??
?? ??? ?sum++;
?? ??? ?PrintChess();
?? ??? ?return;
?? ?}?
?? ?for(int i=0;i<8;i++){
?? ??? ?int a = x + move[i][0];?? ??? ?//拿到當(dāng)前馬位置相鄰的 8 個(gè)日字的 x 坐標(biāo)?
?? ??? ?int b = y + move[i][1];?? ??? ?//拿到當(dāng)前馬位置相鄰的 8 個(gè)日字的 y 坐標(biāo)?
?? ??? ?if(chessboard[a][b] == 0){?? ?//判斷當(dāng)前馬位置相鄰的日字是否已被訪問(wèn)?
?? ??? ??? ?cnt++;?? ??? ??? ??? ??? ??
?? ??? ??? ?chessboard[a][b]=cnt;?? ?//標(biāo)志已被訪問(wèn)
?? ??? ??? ?Horse(a,b);?? ??? ??? ? ?? ?//從當(dāng)前馬的位置繼續(xù)往下訪問(wèn)
?? ??? ??? ?cnt--;?? ??? ??? ??? ??? ?
?? ??? ??? ?chessboard[a][b]=0; ?? ?//回溯回來(lái)修改其相鄰的日字的訪問(wèn)情況?
?? ??? ?}
?? ?}
}
?
//輸出馬踏棋盤(pán)的解?
void PrintChess(){
?? ?cout<<endl<<"馬踏棋盤(pán)第 "<<sum<<"組解為:"<<endl;
?? ?int i,j;
?? ?for(i=2;i<10;i++){
?? ??? ?for(j=2;j<10;j++){
?? ??? ??? ?cout<<" ?"<<chessboard[i][j];?
?? ??? ?}
?? ??? ?cout<<endl;
?? ?}?
}
【問(wèn)題的解】:只列出量?jī)山M解,其余未列出:

【代碼展示2】:貪心算法求解,列出從(2,2)位置出發(fā)的合適解,局部最優(yōu):
#include <iostream>
#include <stdlib.h>
?
using namespace std;
?
/*?
typedef struct{
?? ?int x;?? ??? ??? ?//記錄當(dāng)前馬位置的 x 坐標(biāo)?? ??? ?
?? ?int y;?? ??? ??? ?//記錄當(dāng)前馬位置的 y 坐標(biāo)?
?? ?int i;?? ??? ??? ?//記錄從當(dāng)前馬的位置前往下一個(gè)日字的序號(hào) i (0<i<8)?
}StackHorse;?
*/
?
int StackHorse[100][3]={0};?? ??? ??? ?//申請(qǐng)一個(gè)??臻g(里面存儲(chǔ)的就是 x,y,i三個(gè)具體的變量值),來(lái)標(biāo)記馬走的具體位置?
int chessboard[12][12] = {0};?? ??? ?//記錄 8 * 8棋盤(pán)馬走的具體腳印?
int cnt = 1;?? ??? ??? ?//標(biāo)記馬已走的方格數(shù)
int move[8][2]={ {2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};?? ?//初始馬當(dāng)前位置向其周?chē)噜彴藗€(gè)日字的 x,y的偏移量
?
//輸出馬踏棋盤(pán)的解?
void PrintChess();
//馬踏棋盤(pán)遞歸過(guò)程
void Horse(int x,int y);
?
int main(void){
?? ?int i,j;
?? ?for(i=0;i<12;i++){?? ??? ?//初始化馬踏棋盤(pán)的具體值(0代表未被訪問(wèn),1代表已被訪問(wèn),-1代表新加的最外面兩層)?
?? ??? ?for(j=0;j<12;j++){
?? ??? ??? ?if(i==0 || i==1 || i==10 || i==11 || j==0 || j==1 || j==10 || j==11){
?? ??? ??? ??? ?chessboard[i][j]=-1;
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?Horse(2,2);?? ??? ?//從 (2,2)的位置開(kāi)始跑,求得馬踏棋盤(pán)的一組解
?? ?PrintChess();
?? ?return 0;?
}?
?
//非遞歸求一組解的過(guò)程
void Horse(int x,int y){
?? ?int top=0,i=0;
?? ?int a,b;?? ??? ??? ??? ?//記錄當(dāng)前馬位置附近的日字坐標(biāo)
?? ?chessboard[x][y]=1;?? ?//標(biāo)記當(dāng)前起始位置已被訪問(wèn)?
?
?? ?StackHorse[top][0]=StackHorse[top][1]=2;?? ?//記錄當(dāng)前馬的位置
?? ?while(cnt < 64){
?? ??? ?for(;i<8;i++){
?? ??? ??? ?a = x + move[i][0];
?? ??? ??? ?b = y + move[i][1];
?? ??? ??? ?if(chessboard[a][b] == 0){?? ??? ?//如果當(dāng)前馬位置附近的日字沒(méi)有被訪問(wèn)?
?? ??? ??? ??? ?break;?? ??? ??? ??? ??? ??? ?//跳出循環(huán)?
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if(i<8){?? ??? ??? ??? ??? ?//能夠訪問(wèn)當(dāng)前馬位置附近的日字?
?? ??? ??? ?chessboard[a][b]=++cnt;
?? ??? ??? ?StackHorse[top][2]=i;?? ?//記錄訪問(wèn)當(dāng)前馬位置附近的日字序號(hào)(0<i<8)
?? ??? ??? ?top++;?? ??? ??? ??? ??? ?//top指向新的棧頂
?? ??? ??? ?StackHorse[top][0]=a;?? ?//向新的棧頂放入馬踏入的 x坐標(biāo)?? ?
?? ??? ??? ?StackHorse[top][1]=b;?? ?//向新的棧頂放入馬踏入的 y坐標(biāo)?
?? ??? ??? ?x=a;?? ??? ??? ??? ??? ?//標(biāo)記新的 x?
?? ??? ??? ?y=b;?? ??? ??? ??? ??? ?//標(biāo)記新的 y?
?? ??? ??? ?i=0; ?? ??? ??? ??? ??? ?//從棧頂馬位置開(kāi)始尋找附近的 8 個(gè)日字?
?? ??? ?}
?? ??? ?else{?? ??? ??? ?//沒(méi)有在當(dāng)前馬位置附近找到符合條件的日字 ?
?? ??? ??? ?cnt--;?? ??? ??? ??? ?//回溯?
?? ??? ??? ?chessboard[x][y]=0;
?? ??? ??? ?top--;?? ??? ?//出棧
?? ??? ??? ?x=StackHorse[top][0];?? ??? ?//拿到當(dāng)前馬位置的 x 坐標(biāo) ?
?? ??? ??? ?y=StackHorse[top][1];?? ??? ?//拿到當(dāng)前馬位置的 y 坐標(biāo)?
?? ??? ??? ?i=StackHorse[top][2];?? ??? ?//拿到當(dāng)前馬位置前往下一日字的序號(hào)?
?? ??? ??? ?i++; ?? ??? ??? ??? ??? ??? ?//繼續(xù)搜索從當(dāng)前馬位置訪問(wèn)的日字序號(hào)的下一位置繼續(xù)訪問(wèn)?
?? ??? ?}?
?? ?}?
?? ?
}?
?
//輸出馬踏棋盤(pán)的解?
void PrintChess(){
?? ?cout<<"馬踏棋盤(pán)一組解為:"<<endl;
?? ?int i,j;
?? ?for(i=2;i<10;i++){
?? ??? ?for(j=2;j<10;j++){
?? ??? ??? ?cout<<" ?"<<chessboard[i][j];?
?? ??? ?}
?? ??? ?cout<<endl;
?? ?}?
}【問(wèn)題的解】:列出一組解:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++數(shù)據(jù)封裝以及定義結(jié)構(gòu)的詳細(xì)講解
這篇文章主要詳細(xì)講解了C++數(shù)據(jù)封裝以及定義結(jié)構(gòu),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
Qt將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出為html
這篇文章主要為大家詳細(xì)介紹了Qt如何實(shí)現(xiàn)將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出為html,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12
詳解C++異常處理(try catch throw)完全攻略
這篇文章主要介紹了詳解C++異常處理(try catch throw)完全攻略,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
???????C語(yǔ)言實(shí)現(xiàn)單鏈表基本操作方法
這篇文章主要介紹了???????C語(yǔ)言實(shí)現(xiàn)單鏈表基本操作方法,文章圍繞主題展開(kāi)詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05

