残缺棋盘问题c语言_算法的经典问题

注:本帖主要进行个人记录以及思考

1.八后问题:

百科介绍:八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

Problem Formulation :

initial state:没有棋子在棋盘上

goal state:八个皇后都在棋盘上,任意两个皇后都不能处于同一行、同一列或同一斜线上

Actions:这里开始的情况有两种,一种是将queen放到棋盘左上角,这样它不会受到任何queen的攻击;另一种是随机进行摆放。

Path cost: 1 per move

递归解法:

递归是非常经典的一种解法

c语言版本:

/八皇后递归解法

#include<iostream>

using namespace std;

int queen[8]={-1,-1,-1,-1,-1,-1,-1,-1};

int count=0;

bool available(int pointi,int pointj){//判断某个皇后是否与已有皇后冲突

for(int i=0;i<pointi;i++){

if(pointj==queen[i])return false;//同一列拒绝

if((pointi-i)==(pointj-queen[i]))return false;//同一主对角线拒绝

if((pointi-i)==(queen[i]-pointj))return false;//同一副对角线拒绝

}

return true;

}

void findSpace(int queenNumber){//在第queenNumber行找能放皇后的位置

for(int i=1;i<9;i++){//从1~8遍历这一行的八个空位

if(available(queenNumber,i)){

//如果可以放这个位置就记录下第queenNumber个皇后的位置

queen[queenNumber]=i;

if(queenNumber==8){//如果八个皇后都放满了统计一下

count++;

return;

}

int nextNumber=queenNumber+1;//还有皇后没放递归放下一个皇后

findSpace(nextNumber);

}

}

queen[--queenNumber]=-1;//如果这一行没有可放的位置说明上一行皇后放的位置不行,要为上一个皇后寻找新的可放位置

return;

}

int main(){

findSpace(1);//从(1,1)开始递归好理解

cout<<count<<endl;

return 0;

}

这里借用是的csdn上一个大佬c语言写的解法,所以把原大佬的代码和网址都放上来看看~

CSDN-专业IT技术社区-登录​blog.csdn.net

2.“Missionaries & Cannibals” 传道士与野人问题

三个传教士和三个食人族来到一条河边。有一艘可坐两个人的划艇。如果食人族的数量超过了在河两岸的传教士,传教士就会被吃掉。

哈哈,这个问题暂时跳过

3.Tower of Hanio 汉诺塔问题

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

这是个递归问题,上学期最后一节java的lecture上接触到的,为什么记忆如此深刻呢,因为我到现在才想明白....

话不多说,我们来简单描述一下思路。

汉诺塔问题为什么让人迷惑呢?如果和先前的我一样没有一个整体的思路,只会一步步试验的话,就完全解决不了问题。那么如何吧这个问题简化分解掉呢?

这就是算法里的merge sort了,我们首先要把问题细分为小问题。我们把目标柱称为c柱,中转柱(实际上他不一定一直是中转柱,但是为了区别我还是命名为中转柱)称为b柱,最后把初始柱称为a柱。

这里我们可以确定,我们一定是先把第六十四个disk放到c柱上,那么这个时候我们的a柱就只有一个disk,其他63个disk都在b柱上,并且in order。

下一步我们需要干什么呢?我们需要把第63个disk取出,放到c柱上,这个时候其余62个disk一定是在a柱上。

这样一看是不是就把我们递归的重复行为弄清楚了?然后我们的basic case便是n=1的时候,于是我们可以写下个一个思路。

ef4969f90e338f1109a8e3e75f08c71e.png

当然这个是非常简单的,那么如何执行里面的move呢?

public static void resolve(int n, Stack<Integer> a, Stack<Integer> b, Stack<Integer> c) {

if (n==0) return;

resolve(n-1, a, c, b);

c.push(a.pop());

resolve(n-1, b, a, c);

}

这是直接捉的一位大佬的代码,我们的中转柱的位置不变,就是abc三个变量中中间那个,,然而我们通过抽象化的表达,用柱子上的disk数目来表达柱子,我们在将source柱子上第一个disk挪到中转柱上后,改变了我们放置下一个disk的柱子,也就是我们将b柱上的disk转移到原先的a柱上(这个时候a为中转柱),一直重复这个行为,直到n=0。

可能表达不大清楚!见谅!

附上大佬直通地址:

汉诺塔问题 - Antineutrino - 博客园​www.cnblogs.com
75f0fecf91052ad51b1311b2f304453b.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值