回溯法第3题—n皇后问题

[问题描述]

在一个国际棋盘上,放置n个皇后(n<10),使她们相互之间不能进攻。求出所有布局。

输入:n

输出:每行输出一种方案,每种方案顺序输出皇后所在的列号,每个数之间用空格隔开。

[样例输入]

4

[样例输出]

2 4 1 3
2 1 4 2

[问题分析]

我想这大概是回溯法最经典的一个问题了吧,开一个函数判断一下当前位置是否能放即可。

这里有一个小技巧,就是对皇后进行编号,对应着数组的下标,就可以很容易的满足第一个条件——所有皇后不能在同一行上。

然后数组元素则代表皇后所在的列数,满足第二个条件——所有皇后不能在同一列上,就有a[k]<>a[i](for i:=1 to k-1)

条件三:所有皇后不能出现在对角线上;

这里面所谓的对角线是棋盘单个矩形方格的对角线,即斜率为1或-1的直线。

由数学知识可以得到当斜率为1时,有:a[i]-a[k]=i-k;斜率为-1时,有:a[i]-a[k]=k-i;

由此可以得到总的公式:abs(a[i]-a[k])=abs(i-k)

分析完了,上代码,下面是我写的(代码很短,最喜欢的就是短代码)

//刚开始我感觉有些难理解,于是写了很多注释

var a:array[1..100] of integer;//用行号作为下标编号,避免行号重复
    n:integer;
function can(k,i:integer):boolean;//i代表第k行的第i列
var j:integer;
begin
   for j:=1 to k-1 do
    if (abs(a[j]-i)=abs(j-k))or(i=a[j]) then exit(false);
    // (i=a[j])表示k和j在同一列上,(abs(a[j]-i)=abs(j-k))表示k和j在对角线上
   exit(true);
end;
procedure try(k:integer);
 var i:integer;
begin
  if k>n then
    begin
     for i:=1 to n do write(a[i],‘ ‘);writeln;end
   else
     for i:=1 to n do//从第k行的每一列搜索
      if can(k,i) then//如果k可以放在第i列上
        begin
          a[k]:=i;
          try(k+1);//搜索下一行
        end;
end;
begin
 readln(n);
 try(1);//从第一行开始一行一行搜索
end.

下面是标准程序

var
  a:array  [1..100]  of  integer;
  n,p:integer;
function  find(k,i:integer):boolean;
var    j:integer;
       yes:boolean;
begin
  yes:=true;
 for  j:=1  to  k-1  do
   if  (abs(a[j]-i)=abs(j-k))or(i=a[j])  then  yes:=false;
 find:=yes
end;
procedure print;
var  i:integer;
begin
  p:=1;
  for  i:=1  to  n  do
    write(a[i]:5);
  writeln
end;
procedure  try(k:integer);
var  i:integer;
begin
 if  k>n  then  print
  else
    for i:=1  to  n  do
        if  find(k,i)  then
          begin
            a[k]:=i;
            try(k+1);
          end;
    if (p=0)and(k=1)and(a[k]=3) then writeln(‘no solute!‘)
end;
begin
assign(input,‘word.in‘);
reset(input);
assign(output,‘word.out‘);
rewrite(output);
p:=0;
readln(n);
try(1);
end.

关于n皇后的其他问题,可以参考百度百科http://baike.baidu.com/view/698719.htm

通过看标准程序,发现它总是运用许多的过程和函数,看起来思路比较清晰。这启示我们要学会写模块化的程序,把大问题转化为许多小问题,然后逐个击破。

回溯法第3题—n皇后问题,布布扣,bubuko.com

时间: 2024-12-23 04:42:09

回溯法第3题—n皇后问题的相关文章

回溯法第4题&mdash;置棋问题

[问题描述] 在m*n的主格中任意指定x个格子构成一个棋盘,在任一个构成的棋盘上放置k个棋子,要求任意两个棋子不得位于同一行或同一列上,要求输出满足条件的所有方案.(注意棋盘是稀疏的,即x<m*n/2.1<m,n<10). 编程要求: 1.对给定的一个棋盘,求出该棋盘可放置的最多的棋子数p. 2.记di为该棋盘上放置i个棋子时的方案总数(1<i<p),其中经旋转和镜面反射而得的方案记为不同方案,对每一个i,求出相应的di. 3.程序应能够连续处理多个棋盘,对每一个棋盘,输出p

回溯法第2题—邮票问题

[问题描述] 设有已知面额的邮票m种,每种有n张.问:用总数不超过n张的邮票进行组合,能组合的邮票面额中可以连续出现的面额数最多有多少? (1<=m<=100,1<=n<=100,1<=邮票面额<=225) 输入:第一行:n和m的值,中间用一空格隔开. 第二行:a[1..m](面额),每个数中间用一空格隔开.输出:连续面额数的最大值 [样例输入] 4 3 1 2 4 [样例输出] 14 [问题分析] 我写的程序 var a:array[0..100]of integer

回溯法第1题—数字排列问题

[问题描述] 列出所有从数字1到数字n的连续自然数的排列,要求所产生的任一数字序列中不允许出现重复的数字. 输入:n(1<=n<=9) 输出:由1~n组成的所有不重复的数字序列,每行一个序列. [样例输入] 3 [样例输出] 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 [问题分析] 这题要求输出n个数的全排列(从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列.当m=n时所有的排列情况叫全排列). 显然也没有什

回溯法第7题—圆盘移动问题

[问题描述]从左向右依次安放4根细柱A,B,C,D.在A柱上套有n(n<=20)个直径相同的圆盘,从上到下一次用连续的小写字母a,b,c,...编号,将这些圆盘经过B,C单向的移动到D柱上(即不允许从右向左移动.圆盘可在B,C中暂存).要求找到从A柱初始状态到D柱目标状态的移动过程.输入:第一行是D柱上的圆盘总数,第二行是D柱上由下到上的圆盘的序列.输出:是一个文件.该文件的每一行为一个形如"k m l"的字母序列,其中k为圆盘编号,m为k盘原先的柱号,l为目标柱号.如果不能生成

回溯法第7题&mdash;圆盘移动问题

[问题描述]从左向右依次安放4根细柱A,B,C,D.在A柱上套有n(n<=20)个直径相同的圆盘,从上到下一次用连续的小写字母a,b,c,...编号,将这些圆盘经过B,C单向的移动到D柱上(即不允许从右向左移动.圆盘可在B,C中暂存).要求找到从A柱初始状态到D柱目标状态的移动过程.输入:第一行是D柱上的圆盘总数,第二行是D柱上由下到上的圆盘的序列.输出:是一个文件.该文件的每一行为一个形如"k m l"的字母序列,其中k为圆盘编号,m为k盘原先的柱号,l为目标柱号.如果不能生成

回溯法第6题&mdash;0/1字符串问题

[问题描述]输入仅由0/1组成的长度为n的字符串,并且其中不可含有三个连续的相同子串. 输入:字符串的长度n(n<=40). 输出:所有满足条件的字符串的个数[样例输入] 2 [样例输出] 4 [问题分析]设0/1序列的长度为L,x,y,z分别为第三.第二.第一个子串的首指针:初始:x=L;y=L-1;z=L-2;若三个数字不同,dec(x,1);dec(y,2);dec(z,3);直到 (a[z]...a[y-1]=a[y]...a[x-1]=a[x]...a[l]) or (z<=0)再开

回溯法第5题—自然数的拆分问题

[问题描述]输入自然数n,然后将其拆分成由若干数相加的形式,参与加法运算的数可以重复. 输入:待拆分的自然数n. 输出:若干数的加法式子. [样例输入] 7 [样例输出] 7=1+6 7=1+1+5 7=1+1+1+4 7=1+1+1+1+3 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 7=1+1+1+2+2 7=1+1+2+3 7=1+2+4 7=1+2+2+2 7=1+3+3 7=2+5 7=2+2+3 7=3+4 [问题分析] 很明显是数的组合题目,需满足两个条件: (1)

回溯法解数独题

近段时间用到回溯算法的地方比较多,对算法的理解也有深入.今天偶然发现一张照片,是高中时未做完的一道数独题.当时用的是"候选余数法",之后由于太麻烦,就没有做完.不过当时截图保存了,今天突然看到.那时候刚学完C语言,对汉诺塔递归都不是太理解,所以就一直拖到现在. 用C++做的,代码如下 #include<iostream> usingnamespace std;   intsudoku[9][9]={0};   //判断填在空白位置的数字在行.列上是否符合要求 boolJud

暴力回溯法 解八皇后

国际象棋 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. public class _8Queen { //回溯法,暴力解8皇后 private static int ways = 0; //返回解法个数 public static int f8queen() { int[][] board = new int