您的位置:首页 > 其它

poj1321-棋盘-递归搜索

2012-11-25 20:48 246 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: