位运算优化数独

#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector> 

struct Sudoku { 
	private:
		int blk[9], row[9], col[9];
		int A[9][9], lg[1024];
		
		int lowbit(int x) { /// 得到最低二进制位 
			return x & (-x);
		}
		int BLK(int i, int j) { /// 计算某个位置所在的块 
			return (i/3)*3 + (j/3);
		}
	
		std::vector<std::pair<int, int> > pos; /// 记录需要处理的位置 
		void DFS(int d) { /// 填数 
			if(d == pos.size()) {
				for(int i = 0; i <= 8; i ++) {
					for(int j = 0; j <= 8; j ++) {
						printf("%d ", A[i][j]);
					}
					putchar('\n');
				}
				putchar('\n');
			}else {
				int x = pos[d].first, y = pos[d].second;
				int avai = row[x] & col[y] & blk[BLK(x, y)];
		
				while(avai) {
					int n = lowbit(avai); /// 找到最低比特并尝试 
					avai ^= n;
					n = lg[n]; /// 找到对应的数字 
					
					A[x][y] = n;
					blk[BLK(x, y)] ^= (1<<(n-1));
					row[x] ^= (1<<(n-1));
					col[y] ^= (1<<(n-1));
					
					DFS(d + 1); /// 递归选择下一个位置 
					
					A[x][y] = 0;
					blk[BLK(x, y)] ^= (1<<(n-1));
					row[x] ^= (1<<(n-1));
					col[y] ^= (1<<(n-1));
				}
			}
		}
		
	public:
		Sudoku() {
			for(int i = 1; i <= 9; i ++) { /// 预处理取对数 
				lg[1<<(i-1)] = i;
			}
			for(int i = 0; i <= 8; i ++) {
				blk[i] = row[i] = col[i] = 0;
			}
			for(int i = 0; i < 8; i ++) {
				for(int j = 0; j < 8; j ++) {
					A[i][j] = 0;
				}
			}
		}
		int Solve(int B[9][9]) { /// B[i][j] = 0 表示该位置没有数 
			for(int i = 0; i <= 8; i ++) {
				for(int j = 0; j <= 8; j ++) { /// 坐标 [0, 8] 
					A[i][j] = B[i][j];
					if(A[i][j] != 0) {
						blk[BLK(i, j)] |= (1 << (A[i][j]-1));
						row[i] |= (1 << (A[i][j]-1));
						col[j] |= (1 << (A[i][j]-1)); /// 处理行列和块 
						/// col[j] 写成了 col[i] 调试了一天 qwq 
					}else {
						pos.push_back(std::make_pair(i, j));
					}
				}
			}
			for(int i = 0; i <= 8; i ++) {
				blk[i] = ((1<<9)-1) ^ blk[i]; /// 取反 
				row[i] = ((1<<9)-1) ^ row[i];
				col[i] = ((1<<9)-1) ^ col[i];
			}
			DFS(0);
			return 0;
		}
};

int B[9][9];
int main() {
	Sudoku* tmp = new Sudoku;
	for(int i = 0; i <= 8; i ++) {
		for(int j = 0; j<= 8; j ++) {
			scanf("%d", &B[i][j]);
		}
	}
	tmp -> Solve(B);
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值