【作业】数独

题目

  1. 从1~9的数,填到行列数为9的矩阵中,使他们行列都不出现相同数字,且每3*3行列中也不能出现相同数字
    例如下面数独
    5, 3, 4| 6, 7, 8| 9, 1, 2,
    6, 7, 2| 1, 9, 5| 3, 4, 8,
    1, 9, 8| 3, 4, 2| 5, 6, 7,
    --------|----------|-----------
    8, 5, 9| 7, 6, 1| 4, 2, 3,
    4, 2, 6| 8, 5, 3| 7, 9, 1,
    7, 1, 3| 9, 2, 4| 8, 5, 6,
    --------|----------|----------
    9, 6, 1| 5, 3, 7| 2, 8, 4,
    2, 8, 7| 4, 1, 9| 6, 3, 5,
    3, 4, 5| 2, 8, 6| 1, 7, 9,

现给出如下矩阵,0表示没填入数字,求出完整的数独矩阵
5, 3, 0, 0, 7, 0, 0, 0, 0,
6, 0, 0, 1, 9, 5, 0, 0, 0,
0, 9, 8, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 6, 0, 0, 0, 3,
4, 0, 0, 8, 0, 3, 0, 0, 1,
7, 0, 0, 0, 2, 0, 0, 0, 6,
0, 6, 0, 0, 0, 0, 2, 8, 0,
0, 0, 0, 4, 1, 9, 0, 0, 5,
0, 0, 0, 0, 8, 0, 0, 7, 9,

结论

以下都只是我的思考方法

  1. 这个全排序的过程,所以使用f(f(…f(n))的递归方法,遍历整个表从1~9的填入测试能不能生成即可
  2. 为加快遍历,过滤无效的遍历,每行,每列,每3*3矩阵,生成他们的使用数字的情况,如果占用了,后面情况就不必遍历

代码

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <time.h>
#include <assert.h>
#include <random>

class Sudoku {
public:
	static const int ONE_LINE_COUNT = 3;
	static const int LINE_TOTAL_COUNT = ONE_LINE_COUNT * ONE_LINE_COUNT;
	static const int ONE_MAT_COUNT = ONE_LINE_COUNT * ONE_LINE_COUNT;
	static const int TOTAL_COUNT = ONE_MAT_COUNT * ONE_LINE_COUNT * ONE_LINE_COUNT;

	Sudoku() {
		memset(all_datas, 0, sizeof(all_datas));
		memset(this->has_datas, false, sizeof(has_datas));
	}

	Sudoku(std::initializer_list<unsigned char> lst) {
		memset(all_datas, 0, sizeof(all_datas));
		memset(this->has_datas, false, sizeof(has_datas));
		for (int i = 0; i < TOTAL_COUNT; ++i) {
			auto it = lst.begin() + i;
			if (it == lst.end())
				break;
			if (*it > 0) {
				all_datas[i] = *it;
				has_datas[i] = true;
			}
		}
	}

	void set_num(int row, int col, int value) {
		int index = row * LINE_TOTAL_COUNT + col;
		all_datas[index] = value;
		this->has_datas[index] = true;
	}

	bool check() {
		// 行不能重
		char num_counts[9];
		for (int i = 0; i < LINE_TOTAL_COUNT; ++i) {
			memset(num_counts, 0, sizeof(num_counts));
			for (int j = 0; j < LINE_TOTAL_COUNT; ++j) {
				if(num_counts[all_datas[i*LINE_TOTAL_COUNT + j]-1]++ > 1)
					return false;
			}
		}
		// 列不能重
		for (int i = 0; i < LINE_TOTAL_COUNT; ++i) {
			memset(num_counts, 0, sizeof(num_counts));
			for (int j = 0; j < LINE_TOTAL_COUNT; ++j) {
				if (num_counts[all_datas[j*LINE_TOTAL_COUNT+i]-1]++ > 1)
					return false;
			}
		}
		// 3*3
		for (int i = 0; i < ONE_LINE_COUNT; ++i) {
			for (int j = 0; j < ONE_LINE_COUNT; ++j) {
				int mat_index = i * ONE_LINE_COUNT + j;
				memset(num_counts, 0, sizeof(num_counts));
				for (int r = 0; r < ONE_LINE_COUNT; ++r) {
					for (int c = 0; c < ONE_LINE_COUNT; ++c) {
						int index = (r + i) * ONE_LINE_COUNT + c + j * ONE_LINE_COUNT;
						if (num_counts[all_datas[index]-1]++ > 1)
							return false;
					}
				}
			}
		}
		return true;
	}

	bool _try_fill(int row, int col);

	bool try_fill() {
		memset(row_used, false, sizeof(row_used));
		memset(col_used, false, sizeof(col_used));
		memset(mat_used, false, sizeof(mat_used));

		for (int i = 0; i < LINE_TOTAL_COUNT; ++i) {
			for (int j = 0; j < LINE_TOTAL_COUNT; ++j) {
				int index = i * LINE_TOTAL_COUNT + j;
				int ti = this->all_datas[index];
				if (ti > 0) {
					this->set_used(i, j, ti - 1, true);
				}
			}
		}

		return _try_fill(0, 0);
	}

	inline bool is_next_num(int row, int col, int start) {
		int mati_start = row / ONE_LINE_COUNT * LINE_TOTAL_COUNT * ONE_LINE_COUNT + col / ONE_LINE_COUNT * LINE_TOTAL_COUNT;
		int row_start = row * LINE_TOTAL_COUNT;
		int col_start = col * LINE_TOTAL_COUNT;
		int row_index = start;
		if (!row_used[row_index+row_start] && !col_used[row_index+col_start] && !mat_used[row_index+mati_start]) {
			return true;
		}
		return false;
	}

	inline void set_used(int row, int col, int index, bool is_used) {
		int mat_index = row / ONE_LINE_COUNT * LINE_TOTAL_COUNT * ONE_LINE_COUNT + col / ONE_LINE_COUNT * LINE_TOTAL_COUNT;
		int row_index = row * LINE_TOTAL_COUNT + index;
		int col_index = col * LINE_TOTAL_COUNT + index;
		row_used[row_index] = is_used;
		col_used[col_index] = is_used;
		mat_used[mat_index+index] = is_used;
	}

	unsigned char all_datas[TOTAL_COUNT];
	bool has_datas[TOTAL_COUNT];

	bool row_used[TOTAL_COUNT];
	bool col_used[TOTAL_COUNT];
	bool mat_used[TOTAL_COUNT];
};

namespace std {
	std::ostream& operator<<(std::ostream& os, const Sudoku& s) {
		for (int i = 0; i < Sudoku::TOTAL_COUNT; ++i) {
			if (i % Sudoku::LINE_TOTAL_COUNT == 0)
				os << std::endl;
			os << (int)s.all_datas[i] << ", ";
		}
		return os;
	}
};

bool Sudoku::_try_fill(int row, int col){
	int index = row * LINE_TOTAL_COUNT + col;
	if (index >= TOTAL_COUNT) {
		bool res = this->check();
		return res;
	}
	if (!this->has_datas[index]) {
		for (int i = 0; i < LINE_TOTAL_COUNT; ++i) {
			bool res = this->is_next_num(row, col, i);
			if (res) {
				all_datas[index] = i+1;
				this->set_used(row, col, i, true);
				int next_row = row;
				int next_col = col;
				if (col + 1 >= LINE_TOTAL_COUNT) {
					++next_row;
					next_col = 0;
				}
				else
					++next_col;
				if (_try_fill(next_row, next_col)) {
					return true;
				}
				this->set_used(row, col, i, false);
			}
		}
	}else {
		int next_row = row;
		int next_col = col;
		if (col + 1 >= LINE_TOTAL_COUNT) {
			++next_row;
			next_col = 0;
		}
		else
			++next_col;
		if (_try_fill(next_row, next_col))
			return true;
	}
	return false;
}


void test_soduku() {
	Sudoku s = {
		5, 3, 0, 0, 7, 0, 0, 0, 0, 
		6, 0, 0, 1, 9, 5, 0, 0, 0, 
		0, 9, 8, 0, 0, 0, 0, 0, 0,
		8, 0, 0, 0, 6, 0, 0, 0, 3,
		4, 0, 0, 8, 0, 3, 0, 0, 1,
		7, 0, 0, 0, 2, 0, 0, 0, 6, 
		0, 6, 0, 0, 0, 0, 2, 8, 0, 
		0, 0, 0, 4, 1, 9, 0, 0, 5,
		0, 0, 0, 0, 8, 0, 0, 7, 9
	};
	std::cout << s << std::endl;
	s.try_fill();
	std::cout << s << std::endl;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值