回溯法第4题—置棋问题

[问题描述]

在m*n的主格中任意指定x个格子构成一个棋盘,在任一个构成的棋盘上放置k个棋子,要求任意两个棋子不得位于同一行或同一列上,要求输出满足条件的所有方案。(注意棋盘是稀疏的,即x<m*n/2。1<m,n<10)。

编程要求:

1.对给定的一个棋盘,求出该棋盘可放置的最多的棋子数p。

2.记di为该棋盘上放置i个棋子时的方案总数(1<i<p),其中经旋转和镜面反射而得的方案记为不同方案,对每一个i,求出相应的di。

3.程序应能够连续处理多个棋盘,对每一个棋盘,输出p和d1,d2,…,dp,只需输出数字,不必输出具体方案。

输入:第一行是两个数字,代表第一个棋盘的m和n,以下为一个仅由0、1组成的m×n矩阵,某一个位置值为1表示相应的格子在这个棋盘上,为0表示相应的格子不在棋盘上。

输出:第一行是棋盘可放置的最多的棋子数p;

第二行分别列出从1个棋子到放p个棋子的方案总数。

[样例输入]

5 5
0 1 1 1 0
0 1 0 0 0
1 1 1 0 0
0 0 1 0 0
0 0 1 1 0

[输出样例]

the maxnumber=4
1:10
2:28
3:24
4:5

[问题分析]

这道题跟n皇后的题目很像,只不过这道题并没有要求每行每列都必须有棋子,因此为了达到最大放置,有些行或列可以不必放入棋子。

由于x<1/2mn,很稀疏,按照行来搜索肯定效率很低,于是可以把棋盘所有的格子开一个数组记录下来。

下面给出我的代码:

var  chess:array[1..50]of record
                    x,y:integer;
                end;//本数组用来记录棋盘的格子号
      sum,m,n,p:byte;
      line,row:array[1..10]of boolean;//line,row表示某行,某列有无棋子的情况,true表示无,false表示有
      d:array[1..10] of longint;//用来记录放置第i个棋子的方案数,请思考为什么数组上限是10?    procedure init;//初始化
var i,j,int:integer;
begin
  fillchar(row,sizeof(row),true);
  fillchar(line,sizeof(line),true);
  fillchar(d,sizeof(d),0);
  assign(input,‘word.in‘);reset(input);
  assign(output,‘word.out‘);rewrite(output);
  readln(m,n);
  sum:=0;
  for i:=1 to m do
     for j:=1 to n do
       begin
         read(int);
         if  int=1  then
           begin
             inc(sum);
             chess[sum].x:=i;
             chess[sum].y:=j
           end;
       end;
end;
procedure work(next,s:integer);//从第next个可放棋的位置开始寻找第s个棋子可放的一个位置
var i,x,y:integer;
begin
   for i:=next to sum do
     begin
       x:=chess[i].x;y:=chess[i].y;//用x,y变量表示简便
       if line[x] and row[y] then
         begin
           inc(d[s]);line[x]:=false;row[y]:=false;
           work(i+1,s+1);
           line[x]:=true;row[y]:=true;//回溯
         end;
    end;
end;
procedure print;
var i:integer;
begin
  for i:=1 to 10 do if d[i]=0 then break;
  p:=i-1;
  writeln(‘the maxnumber=‘,p);
  for i:=1 to p do
     writeln(1,‘:‘,d[i]);
  close(input);close(output);
end;
begin
  init;
  work(1,1);
  print;
end.

标准程序:

var
   chess:array [1..50] of  record
                              x,y:integer;
                           end;
   row,col:array  [1..10]  of  boolean;
   d:array [1..10]  of  longint;
   m,n,p,sum:byte;
 procedure  init;
 var  i,j,int:integer;
 begin
   sum:=0;
   for i:=1 to m do
     for j:=1 to n do
       begin
         read(int);
         if  int=1  then
           begin
             inc(sum);
             chess[sum].x:=i;
             chess[sum].y:=j
           end;
       end;
       fillchar(row,sizeof(row),true);
       fillchar(col,sizeof(col),true);
       fillchar(d,sizeof(d),0);
 end;
 procedure work(next,s:integer);
 var
  i,x,y:integer;
 begin
   for  i:=next  to  sum  do
     begin
       x:=chess[i].x;y:=chess[i].y;
       if  (row[x])and(col[y])  then
         begin
           inc(d[s]); row[x]:=false;col[y]:=false;
           work(i+1,s+1);
           row[x]:=true;col[y]:=true
         end;
     end;
 end;
 procedure print;
 var i:integer;
 begin
   for  i:=10 downto 1  do
     if  d[i]>0  then break;
   p:=i;
   writeln(‘the maxnumber=‘,p);
   for  i:=1  to  p  do
     writeln(i,‘:‘,d[i])
 end;
 begin
  assign(input,‘word.in‘);reset(input);
  assign(output,‘word.out‘);rewrite(output);
  readln(m,n);
  while (m<>0) and (n<>0) do
    begin
      init;
      work(1,1);
      print;
      readln(m,n);
    end;
 end.

我的和标准程序写的差不多,只看一个就行了。

这道题确实是很简单,但是我却把变量名打反了……然后调了一晚上…………很浪费时间

以后写完程序不要急着去编译,运行,然后出错了再watch……应该先从头到尾仔仔细细的看一遍代码……

这样可以节省很多时间,也可以避免不必要的麻烦……

特别是刷水题的时候尤其要注意这一点……………………

吸取教训………………

回溯法第4题—置棋问题,布布扣,bubuko.com

时间: 2024-10-11 16:33:52

回溯法第4题—置棋问题的相关文章

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

[问题描述] 在一个国际棋盘上,放置n个皇后(n<10),使她们相互之间不能进攻.求出所有布局. 输入:n 输出:每行输出一种方案,每种方案顺序输出皇后所在的列号,每个数之间用空格隔开. [样例输入] 4 [样例输出] 2 4 1 3 2 1 4 2 [问题分析] 我想这大概是回溯法最经典的一个问题了吧,开一个函数判断一下当前位置是否能放即可. 这里有一个小技巧,就是对皇后进行编号,对应着数组的下标,就可以很容易的满足第一个条件——所有皇后不能在同一行上. 然后数组元素则代表皇后所在的列数,满足

回溯法第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

poj 1321 棋盘问题 (回溯法)

棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69951   Accepted: 33143 Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C. Input 输入含有多组测试数据. 每组数据的第一行是两个正整数,n k,用一个空格隔开,表示