poj1321棋盘递归搜索

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
#include <set>     //本意是用set检查是否冲突,结果用set会超时
#include <cstdio>
using namespace std;
int rows[9];//check collision
int cols[9];//check collision
int top = 0;//pointer to rows, cols
char board[9][9];//棋盘
int pos_sum[9][9];//从board[0][0]到board[i][j]累计'#'数
int n, k;//n*n棋盘,放k个棋子
int cnt;//方案数
int total = 0;//棋盘上#的总个数

bool exist(int row, int col){//检查是否冲突,冲突返回true
	for(int i = 0; i < top; i++){
		if(rows[i] == row || cols[i] == col){
			return true;
		}
	}
	return false;
}
void put(int row, int col, int k){//try to put k chesses from board[row][col]
	if(k == 0){
		cnt++;
		return;
	}
	if(total - pos_sum[row][col] + 1 < k || n - row < k){//剪枝
		return;
	}
	for(int i = row; i < n; i++){
		for(int j = ((i == row)?col:0); j < n; j++){//这个地方意思是对row这行,从col列开始遍历,对之后的行,从第0列开始遍历。也可以写成两个循环,不过那样又太麻烦,没想到特别好的写法
			//开始在这里犯了一个严重的错误:
			//for(int i = row...)
			//	for(int j = col...)
			//	这个是检查右下角的矩阵!而不是从这个点开始的所有点!!
			if(board[i][j] == '#' && !exist(i, j)){
				rows[top] = i;
				cols[top] = j;
				top++;
				if(j + 1 <= n - 1){
					put(i, j + 1, k - 1);
				}else if(i + 1 <= n - 1){
					put(i + 1, 0, k - 1);
				}else if(k - 1 == 0){//没位置了,同时也放完了
					cnt++;
				}
				top--;
			}
		}
	}
}
int main()
{
	while(scanf("%d%d", &n, &k) != EOF && n != -1){
		cnt = 0;
		for(int i = 0; i < n; i++){
			scanf("%s", board[i]);
		}
		for(int i = 0; i < n; i++){
			for(int j = 0; j < n; j++){
				if(board[i][j] == '#'){
					pos_sum[i][j] = total + 1;
					total++;
				}
			}
		}
		put(0,0,k);
		printf("%d\n", cnt);
	}
	return 0;
}

  这个代码风格也是挺糟糕的,到处是全局变量,不过这样程序写起来很方便

改进:

#include <set>
#include <cstdio>
using namespace std;
int rows[9];//check collision
int cols[9];
int top = 0;//pointer to rows, cols
char board[9][9];
int pos_sum[9][9];
int n, k;
int cnt;
int total = 0;

bool exist(int row, int col){//检查是否冲突,冲突返回true
    for(int i = 0; i < top; i++){
        if(rows[i] == row || cols[i] == col){
            return true;
        }
    }
    return false;
}
void put(int row, int k){//try to put k chesses from board[row][0]
    if(k == 0){
        cnt++;
        return;
    }
    //k > 0
    if(n - row < k || total - pos_sum[row][0] + 1 < k){//剪枝
        return;
    }
    for(int i = row; i < n; i++){
        for(int j = 0; j < n; j++){
            if(board[i][j] == '#' && !exist(i, j)){
                rows[top] = i;
                cols[top] = j;
                top++;
                //本行不会再放,一定是从下一行放
                put(i + 1, k - 1);//i + 1 >= n is also ok
                top--;
            }
        }
    }
}
int main()
{
    while(scanf("%d%d", &n, &k) != EOF && n != -1){
        cnt = 0;
        for(int i = 0; i < n; i++){
            scanf("%s", board[i]);
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(board[i][j] == '#'){
                    pos_sum[i][j] = total + 1;
                    total++;
                }
            }
        }
        put(0,k);
        printf("%d\n", cnt);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fstang/p/2787906.html