• 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;
    }
  • 相关阅读:
    状压dp(基础)
    JVM调优实战
    MySql5.6性能优化
    淘淘商城_day09_课堂笔记
    【剑指offer】找出数组中任意一个重复的数字,C++实现
    【剑指offer】字符串转换为数字,C++实现
    【剑指offer】圆圈中最后剩下的数字(约瑟夫问题),C++实现
    【剑指offer】扑克牌的顺子,C++实现
    【剑指offer】n个骰子的点数,C++实现
    android webview 漏洞背后的节操
  • 原文地址:https://www.cnblogs.com/fstang/p/2787906.html
Copyright © 2020-2023  润新知