Poj 1321 棋盘问题(搜索)

Description

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

Input

输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

Output

对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

Sample Output

2
1

分析:回溯法,这题要求的是方案数量。刚开始的时候就是用二维数组暴搜,但是就是不知道怎么判断这个解是不是重复的,因为棋子没有区别,所以4个位置放4个棋子有24种方法,但是如果棋子相同的话就是一种了。想想每次排序再存起来判断的话会超时,所以就采取了按行(以按行为例)或按列搜索的方法来解。从第一行开始搜索,如果这一行中有满足条件的位置就再搜索下一行,如果这一行没有的话就搜索下下行。再加个判断条件,如果超过N的话就结束,这样到了最后一行,有结果就加一,没有就回溯。有了按按搜索这样一个顺序,再加上判断条件,就不会出现重复的排列了。

import java.util.Scanner;

public class Main {

	static int N, M;
	static boolean[][] path;
	static boolean[] xP;
	static boolean[] yP;
	static int ans;

	static void DFS(int row, int n) {
		if (n == M) {
			ans++;
			return;
		}
		if (row > N) //配合下面DFS(row+1,num); 语句使用,避免搜索越界
			return;
		
		for (int j = 1; j <= N; j++) {
			
			if (path[row][j] && !yP[j] && !xP[row]) {
				yP[j] = true;
				xP[row] = true;
				DFS(row + 1, n + 1);
				yP[j] = false;
				xP[row] = false;

			}
		}
		DFS(row + 1, n);// 如果该行没有合适的位置,搜索下一行。
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (true) {
			N = sc.nextInt();
			M = sc.nextInt();
			if (N == -1) {
				break;
			}
			String in[] = new String[N + 1];

			path = new boolean[10][10];
			xP = new boolean[10];
			yP = new boolean[10];
			ans = 0;
			for (int i = 1; i <= N; i++) {
				in[i] = sc.next();
				for (int j = 1; j <= N; j++) {
					if (in[i].charAt(j - 1) == '#') {
						path[i][j] = true;
					}
				}
			}
			DFS(0, 0);
			System.out.println(ans);
		}

	}
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/AndyDai/p/4734097.html