DFS剪枝——poj3074数独

题目连接

Description

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

. 2 7 3 8 . . 1 .
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .
Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input
.2738…1…1…6735…293.5692.8…6.1745.364…9518…7…8…6534.
…52…8.4…3…9…5.1…6…2…7…3…6…1…7.4…3.
end

Sample Output
527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

搜索思路:从没有数字的格子开始递归搜索,如果当前填入的数字不合法,则填入下一个当前状态合法的数据,直到所有数据填写完毕。
剪枝优化策略:
1.优化搜索顺序:从当前能填合法数字最少的位置开始填数字。
2.如何最快的求出当前的合法数字,以及某个点填入数字后,其他点状态的更新。
解决办法:
对于每行,每列,每个九宫格,分别用9位二进制数来表示那些数字可以填。
例如:row[i] = 000010101(二进制)表示第i行可以填入1,3,5
而对于某个位置的状态,则为该点所在上述三种状态的&运算

int get(int x,int y){
     
    return row[x] & list[y] & block[(x/3)*3+y/3];
}

ac代码:

#include
#include
#include
using namespace std;
const int N = 9;
const int M = (1<<9);
char str[100];
int row[N+2],list[N+2],block[N+2];//行,列和区域
int n;
int cnt[M],map[M];
int a[N+2][N+2];

int get(int x,int y){
     
    return row[x] & list[y] & block[(x/3)*3+y/3];
}

int lowbit(int x){
     
    return x&(-x);
}

bool dfs(int nn){
     
    int i,j;
    if(nn == 81)    return true;
    //找出来最少的选择方案
    int x,y,mint = M-1;//最小数量
    for(i = 0;i<N;i++){
     
        for(j = 0;j<N;j++){
     
            if(a[i][j] != -1)   continue;
            int t = get(i,j);
            if(cnt[t]<cnt[mint]){
     
                x = i,y = j;
                mint = t;
            }
        }
    }
    //当前选择最小的点x,y
    
    while(mint != 0){
     
        int num = map[lowbit(mint)];//当前x,y点的数
        a[x][y] = num;
        row[x] -= 1<<num;
        list[y] -= 1<<num;
        block[(x/3)*3+y/3] -= 1<<num;
        
        //搜索下一层
        
        if(dfs(nn+1)){
     
    //    	cout<
        	return true;
		}
	//	cout<
        //回溯
        a[x][y] = -1;
        row[x] += 1<<num;
        list[y] += 1<<num;
        block[(x/3)*3+y/3] += 1<<num;
        
        //搜索下一个
        mint -= lowbit(mint);
    }
    return false;
}

int main(){
     
    int i,j;
    
    //预处理0——(1<<8)-1的1的个数
    for(i = 0;i<N;i++)  map[1<<i] = i;
    for(i = 0;i<M;i++){
     
        int a = i,cn = 0;
        while(a != 0){
     
            cn++;
            a -= lowbit(a);
        }
        cnt[i] = cn;
    }
    
    while(cin>>str,str[0] != 'e'){
     
        //初始化每一行的状态
        for(i = 0;i<N;i++){
     
            row[i] = list[i] = block[i] = (1<<9)-1;
        }
        
        //对行,列的状态进行更改
        int k = 0;
        int cntt = 0;//填入的数量
        
        for(i = 0;i<N;i++){
     
            for(j = 0;j<N;j++){
     
                if(str[k]!='.'){
     
                    //用0-8表示1-9,更加简单
                    cntt++;
                    int t = str[k]-'1';
                    a[i][j] = t;
                    row[i] -= 1<<t;
                    list[j] -= 1<<t;
                    //i,j点位于的块的位置,x = (i/3)*3+(j/3);
                    int x = (i/3)*3+(j/3);
                    block[x] -= 1<<t;
                }else
                    a[i][j] = -1;
                k++;
            }
        }
        
        dfs(cntt);
        for(i = 0;i<N;i++){
     
            for(j = 0;j<N;j++){
     
                printf("%d",a[i][j]+1);
            }
        }
        cout<<endl;
    }
    
    return 0;
}

你可能感兴趣的:(ACM,算法,dfs)