POJ - 3074 Sudoku (搜索)剪枝+位运算优化

时间:2022-07-28
本文章向大家介绍POJ - 3074 Sudoku (搜索)剪枝+位运算优化,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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

最后终于碰上了位运算优化的题目,虽然学会了发现不难,我们就来看看这个题怎么做!

首先明确一件事,&代表两个状态取交集,这样就更快的到两个状态的共有部分,详解在代码中!

#include<iostream>
#include<queue>
#include<algorithm>
#include<set>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<bitset>
#include<cstdio>
#include<cstring>
#define Swap(a,b) a^=b^=a^=b
#define cini(n) scanf("%d",&n)
#define cinl(n) scanf("%lld",&n)
#define cinc(n) scanf("%c",&n)
#define cins(s) scanf("%s",s)
#define coui(n) printf("%d",n)
#define couc(n) printf("%c",n)
#define coul(n) printf("%lld",n)
#define speed ios_base::sync_with_stdio(0)
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
#define mem(n) memset(n,0,sizeof(n))
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e6+10;
const double esp=1e-9;
//-------------------------------------------------------//

const int N=9;
char a[N*N+N];
int R[9],L[9],C[3][3];
int one[1<<N],mp[1<<N];//通过lowbit,找到每一位1对应的位置
inline int lowbit(int n)
{
    return n&-n;
}
inline void init()//初始化,每个状态位赋值为1
{

    for(int i=0; i<N; i++){
        R[i]=L[i]=(1<<N)-1;
    }

    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            C[i][j]=(1<<N)-1;
}
inline int get(int x,int y) // 找到当前位置能填的状态
{
    return L[y]&R[x]&C[x/3][y/3];
}
bool dfs(int n)
{
    if(n==0)
        return 1;
   //cout<<n<<' ';
    int x,y,mini=10;
    for(int i=0; i<N; i++) //寻找最少填数点
    {
        for(int j=0; j<N; j++)
        {
            if(a[i*N+j]!='.')
                continue;
            int minT=one[get(i,j)];
            if(minT<mini)
            {
                x=i;
                y=j;
                mini=minT;
            }
        }
    }
    //cout<<x<<' '<<y<<endl;
    int T=get(x,y);
   //cout<<T<<endl;
    for(int i=T; i; i-=lowbit(i)) //遍历每一位1所代表的的状态,看不懂状态,打个表就行了。
    {
        int w=mp[lowbit(i)];
        a[x*N+y]=w+'1';
        R[x]-=1<<w;
        L[y]-=1<<w;
        C[x/3][y/3]-=1<<w;
        if(dfs(n-1))
            return 1;
        a[x*N+y]='.';
        R[x]+=1<<(w);
        L[y]+=1<<(w);
        C[x/3][y/3]+=1<<w;
    }
    return 0;
}
int main()
{
    for(int i=0; i< 1<<N; i++)
    {
        int s=0;
        for(int j=i; j; j-=lowbit(j))s++;
        one[i]=s; //统计2的N次方内所有的数的1的个数,这样用到时就不用算了
    }
    for(int i=0;i<N;i++) mp[1<<i]=i;
    while(cin>>a&&a[0]!='e')
    {
        int k=0,cnt=0;
        init();
        for(int i=0; i<N; i++) //预处理,得到还有多少数需要填,处理一下状态
        {
            for(int j=0; j<N; j++,k++)
            {
                if(a[i*N+j]=='.')
                {
                    cnt++;
                    continue;
                };
                int T=(1<<(a[k]-'1'));
                R[i]-=T;//代表这一行的状态中填了a[k]这个数了
                L[j]-=T;
                C[i/3][j/3]-=T;
            }
        }
        if(dfs(cnt))
            cout<<a<<endl;
    }
}