poj 3074

数独问题,暴搜。

有一个优化,优先搜索可填位置少的

同时一个位置一个位置填,一次一个位置就好

可以用二进制储存状态

#include<cstdio>
#include<algorithm>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 15;
int r[MAXN], c[MAXN], k[MAXN];
int lg[1 << 10], num[1 << 10];
char s[MAXN * MAXN], a[MAXN][MAXN];

inline int ID(int i, int j)
{
    return 3 * (i / 3) + j / 3;
}

inline void draw(int x, int y, int z)
{
    r[x] ^= 1 << z;
    c[y] ^= 1 << z;
    k[ID(x, y)] ^= 1 << z;
}

bool dfs(int cnt)
{
    if(cnt == 81) return true;
    int x, y, mint = 10;
    
    REP(i, 0, 9)
        REP(j, 0, 9)
            if(a[i][j] == '.')
            {
                int val = num[r[i] & c[j] & k[ID(i, j)]];
                if(!val) return false;
                if(mint > val)
                {
                    mint = val;
                    x = i, y = j;
                }
            }
            
    int tmp = r[x] & c[y] & k[ID(x, y)];
    for(; tmp; tmp -= tmp & (-tmp))
    {
        int t = lg[tmp & (-tmp)];
        a[x][y] = t + '1';
        draw(x, y, t);
        if(dfs(cnt + 1)) return true;
        draw(x, y, t);
        a[x][y] = '.';
    }
    
    return false;
}

int main()
{
    REP(i, 0, 9) lg[1 << i] = i;
    REP(i, 0, 1 << 9) 
        for(int j = i; j; j -= j & (-j)) num[i]++;
        
    while(scanf("%s", s) && s[0] != 'e')
    {
        int cnt = 0;
        REP(i, 0, 9) c[i] = r[i] = k[i] = (1 << 9) - 1;
        REP(i, 0, 9)
            REP(j, 0, 9)
            {
                a[i][j] = s[i * 9 + j];
                if(a[i][j] != '.') cnt++, draw(i, j, a[i][j] - '1');
            }
            
        dfs(cnt);
        REP(i, 0, 9)
            REP(j, 0, 9)
                s[i * 9 + j] = a[i][j];    
        puts(s);
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/sugewud/p/9896178.html