POJ 2676 Sudoku (dfs|dancing links)

题意:填数独

题解:dfs|dancing links
dancing links肯定更快,两个都写一写吧。

对于dfs解法,可以先存储行、列、宫哪些数字可以填,再对未填的数字进行dfs即可。注意终止条件。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int maxn = 11;
int a[maxn][maxn], t, flag;
bool row[maxn][maxn], col[maxn][maxn], grid[maxn][maxn];
struct node {
    int x, y;
}p[maxn * maxn];
void dfs(int n) {
    if (n == 0) {
        flag = 1;
        return;
    }
    int x = p[n].x;
    int y = p[n].y;
    int z = (x / 3) * 3 + y / 3;
    for (int i = 1; i <= 9; i++) {
        if (!row[x][i] && !col[y][i] && !grid[z][i]) {
            row[x][i] = col[y][i] = grid[z][i] = true;
            a[x][y] = i;
            dfs(n - 1);
            if (flag) return;
            row[x][i] = col[y][i] = grid[z][i] = false;
            a[x][y] = 0;
        }
    }
}
int main() {
    scanf("%d", &t);
    while (t--) {
        int num = 0;
        flag = 0;
        memset(row, 0, sizeof(row));
        memset(col, 0, sizeof(col));
        memset(grid, 0, sizeof(grid));
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char x;
                scanf(" %c", &x);
                a[i][j] = x - '0';
                if (a[i][j]) {
                    row[i][a[i][j]] = true;
                    col[j][a[i][j]] = true;
                    int k = (i / 3) * 3 + j / 3;
                    grid[k][a[i][j]] = true;
                }
                else {  
                    p[++num].x = i;
                    p[num].y = j;
                }
            }
        }
        dfs(num);
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                printf("%d", a[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

dancing links思路(图来自oi-wiki):

dancing links代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
int a[11][11];
struct DLX {
	const static int ROW = 777, COL = 333, SIZE = ROW * COL;
	int L[SIZE], R[SIZE], U[SIZE], D[SIZE];  //模拟指针
	int col[SIZE], row[SIZE]; //所在列 所在行
	int visn, visited[COL]; //用于估价函数
	int sel[ROW], seln; //选择的行
	int sz[COL]; //列元素数
	int total/*节点编号*/, H[ROW];
	void init(int clen) { //初始化列头指针
		for (int i = 0; i <= clen; ++i) {
			L[i] = i - 1; R[i] = i + 1;
			U[i] = D[i] = i; sz[i] = 0;
		}
		for (int i = 0; i < ROW; i++) H[i] = -1;
		for (int i = 0; i < COL; i++) visited[i] = 0; visn = 0; //用于重复覆盖的A*剪枝
		L[0] = clen; R[clen] = 0; total = clen + 1;
	}
	void link(int r, int c) {//行列都是从下标1开始
		U[total] = c; D[total] = D[c];
		U[D[c]] = total; D[c] = total;
		if (H[r] < 0) H[r] = L[total] = R[total] = total;
		else {
			L[total] = H[r]; R[total] = R[H[r]];
			L[R[H[r]]] = total; R[H[r]] = total;
		}
		sz[c]++; col[total] = c; row[total++] = r;
	}
	//-------------------- 精确覆盖 -------------------------
	void remove(const int& c) { //删除c列上所有1元素所在的行
		L[R[c]] = L[c]; R[L[c]] = R[c];
		for (int i = D[c]; i != c; i = D[i])
			for (int j = R[i]; j != i; j = R[j])
				U[D[j]] = U[j], D[U[j]] = D[j], --sz[col[j]];
	}
	void resume(const int& c) { //恢复c列上所有1元素所在的行
		R[L[c]] = L[R[c]] = c;
		for (int i = U[c]; i != c; i = U[i])
			for (int j = L[i]; j != i; j = L[j])
				++sz[col[U[D[j]] = D[U[j]] = j]];
	}
	bool dance(int now) {
		if (R[0] == 0) {
			int x, y, v;
			for (int i = 0; i < now; i++) {
				x = (sel[i] - 1) / 9 / 9;
				y = (sel[i] - 1) / 9 % 9;
				v = (sel[i]) % 9;
				if (v == 0) v = 9;
				a[x][y] = v;
			}
			seln = now;
			return true;
		}
		int c = R[0], i, j;
		for (i = R[0]; i != 0; i = R[i]) //选择元素最少的列c
			if (sz[c] > sz[i]) c = i;
		remove(c);
		for (i = D[c]; i != c; i = D[i]) { //删除与c相连的行i
			for (j = R[i]; j != i; j = R[j]) //删除行元素所在的列j
				remove(col[j]);
			sel[now] = row[i]; //选择此行 保存行号
			if (dance(now + 1)) { //对于不同的题 这个地方常常需要改动
				return true;
			}
			for (j = L[i]; j != i; j = L[j])
				resume(col[j]);
		}
		resume(c);
		return false;
	}
}dlx;
int t;
char s[11];
int main() {
	scanf("%d", &t);
	while (t--) {
	        dlx.init(324);
		for (int i = 0; i <= 8; i++) {
			scanf("%s", s);
			for (int j = 0; j <= 8; j++) {
				a[i][j] = s[j] - 48;
				for (int k = 1; k <= 9; k++) {
					if (a[i][j] != k && a[i][j] != 0) continue;
					int o = i * 9 * 9 + j * 9 + k;
					dlx.link(o, i * 9 + j + 1);
					dlx.link(o, i * 9 + 81 + k);
					dlx.link(o, j * 9 + 81 * 2 + k);
					dlx.link(o, 81 * 3 + (i / 3 * 3 + j / 3) * 9 + k); 
				}
			}
		}
		dlx.dance(0);
		for (int i = 0; i <= 8; i++) {
			for (int j = 0; j <= 8; j++) {
				printf("%d", a[i][j]);
			}
			printf("\n");
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值