在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
21
分析:由于题目要去不同的行和列,因此思路大致是:以行为基准,搜索每一行的各列是否能够放置棋子,再进行下一行的判断。注意回溯的时候的还原。
见代码:
import java.util.*; public class Main { static Scanner in = new Scanner(System.in); static char[][] maze = new char[10][10]; static boolean[]vis = new boolean[10];//每一列的标志数组 static int n,k,cnt; static int sum; static void dfs(int row){ if(cnt>=k){//放到k个棋子 sum++;//方案加一 return; } if(row>=n)//棋盘出界 return; //搜索每一列进行放置 for (int i = 0; i < n; i++) { if(!vis[i]&&maze[row][i]=='#'){ vis[i]=true; cnt++; dfs(row+1); cnt--;//回溯数目 vis[i]=false;// 回溯标志 } } dfs(row+1);//搜索下一行 } public static void main(String[] args) { while(in.hasNext()){ n = in.nextInt(); k = in.nextInt(); if(n==-1&&k==-1) break; String s; for (int i = 0; i < n; i++) { vis[i]=false; s = in.next(); for(int j = 0 ;j< n;j++ ){ maze[i][j]= s.charAt(j); } } cnt=0;sum=0; dfs(0); System.out.println(sum); } } }
反思:对于深搜的过程要把握好的前提是掌握好递归的过程。所以先把递归学习扎实了才是硬道理。还有①对于表示标志数组的维数要灵活变通,需要存储几个状态就是几维的数组。
②深搜前那些量进行了变动,回溯的时候一定不要忘了还原(如果题目需要回溯的话)