poj1321-棋盘-递归搜索
Description
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
每组数据的第一行是两个正整数,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; }

浙公网安备 33010602011771号