标签:style blog http color io for ar 问题
[问题描述]
在一个国际棋盘上,放置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
通过看标准程序,发现它总是运用许多的过程和函数,看起来思路比较清晰。这启示我们要学会写模块化的程序,把大问题转化为许多小问题,然后逐个击破。
标签:style blog http color io for ar 问题
原文地址:http://www.cnblogs.com/cuichen/p/3908433.html