HDU 4069 数独

  好久没做题了,建图搞了好久…… 然后,判是否有多解的时候会把原来的答案覆盖掉…… 这里没注意,弄了一下午……

代码:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <cctype>
#include <time.h>

using namespace std;

const int INF = 1<<30;
const int MAXN = 9*9*4+5;
const int MAXR = 9*9*9+5;
const int MAXNODE = MAXN*MAXR+5;

struct DLX {
// 行编号从1开始,列编号为1~n,结点0是表头结点;结点1~n是各列顶部的虚拟结点
    int n, sz; // 列数,结点总数
    int S[MAXN]; //各列结点数

    int row[MAXNODE], col[MAXNODE]; //各结点行列编号
    int L[MAXNODE], R[MAXNODE], U[MAXNODE], D[MAXNODE]; //十字链表

    int ansd, ans[MAXR]; // 解

    void init(int n)  { //n是列数
        this->n = n;

        //虚拟结点
        for (int i = 0; i <= n; i++) {
            U[i] = i; D[i] = i; L[i] = i-1; R[i] = i+1;
        }
        R[n] = 0; L[0] = n;
        sz = n+1;
        memset(S, 0, sizeof(S));
    }

    void addRow(int r, vector<int> columns) {
        //这一行的第一个结点
        //行没有设头结点,每一行连成一个环形
        int first = sz;
        for (int i = 0; i < columns.size(); i++) {
            int c = columns[i];
            L[sz] = sz-1; R[sz] = sz+1; D[sz] = c; U[sz] = U[c];
            D[U[c]] = sz; U[c] = sz;
            row[sz] = r; col[sz] = c;
            S[c]++; sz++;
        }
        R[sz-1] = first; L[first] = sz-1;
    }

    //顺着链表A,遍历s外的其他元素
    #define FOR(i, A, s) for (int i = A[s]; i != s; i = A[i])

    void remove(int c) { //删除c列
        L[R[c]] = L[c]; R[L[c]] = R[c];
        for (int i = D[c]; i != c; i = D[i]) // 对于每一个c列不为0的所有行
            for (int j = R[i]; j != i; j = R[j]) { //删除这一整行
                U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]]--;
            }
    }

    void restore(int c) { //回连c列
        for (int i = U[c]; i != c; i = U[i])
            for (int j = L[i]; j != i; j = L[j]) {
                U[D[j]] = j; D[U[j]] = j; S[col[j]]++;
            }
        L[R[c]] = c; R[L[c]] = c;
    }

    int flag;

    void dfs(int d) { //d为递归深度
        if (R[0] == 0) { //找到解
            ansd = d; //记录解的长度
            flag++;
            return ;
        }

        //找S最小的C列
        int c = R[0]; //第一个未删除的列
        for (int i = R[0]; i != 0; i = R[i]) if (S[i]<S[c]) c = i;
        remove(c); //删除第c列
        for (int i = D[c]; i != c; i = D[i]) { //用结点i所在的行覆盖第c列
            if (!flag) ans[d] = row[i];
            for (int j = R[i]; j != i; j = R[j]) remove(col[j]); //删除节结点i所在行覆盖第c列
            dfs(d+1);
            if (flag>1) return ;
            for (int j = L[i]; j != i; j = L[j]) restore(col[j]); // 恢复
        }
        restore(c); //恢复
    }

    int solve(vector<int> &v) {
        v.clear();
        flag = 0;
        dfs(0);
        for (int i = 0; i < ansd; i++) v.push_back(ans[i]);
        return flag;
    }
};

const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };

const int SLOT = 0;
const int ROW = 1;
const int COL = 2;
const int SUB = 3;

inline int encode(int a, int b, int c) { return a*81+b*9+c+1; }
inline void decode(int code, int &a, int &b, int &c) {
    code--;
    c = code%9; code /= 9;
    b = code%9; code /= 9;
    a = code;
}

DLX solver;
int Matrix[22][22];
int belong[9][9];
int cnt;

vector<int> columns;

void test() { int *p = 0; (*p) = 0; }

void dfs(int r, int c, int num) {
    belong[r][c] = cnt;
    int t = Matrix[r][c]>>4;
    int nr, nc;
    for (int i = 0; i < 4; i++) if (!(t&(1<<i))) {
        nr = r+dir[i][0]; nc = c+dir[i][1];
        if (!(0<=nr&&nr<9)||!(0<=nc&&nc<9)||belong[nr][nc]!=-1) continue;
        dfs(nr, nc, num+1);
    }
}

void solve() {
    solver.init(9*9*4);
    for (int r = 0; r < 9; r++) {
        for (int c = 0; c < 9; c++) {
            Matrix[r][c] %= 16;
            for (int v = 1; v <= 9; v++) {
                if (Matrix[r][c]!=0 && Matrix[r][c]!=v) continue;
                columns.clear();
                columns.push_back(encode(SLOT, r, c));
                columns.push_back(encode(ROW, r, v-1));
                columns.push_back(encode(COL, c, v-1));
                columns.push_back(encode(SUB, belong[r][c], v-1));
                solver.addRow(encode(r, c, v-1), columns);
            }
        }
    }

    int ans = solver.solve(columns);
    if (ans == 2) { puts("Multiple Solutions"); return; }
    if (ans == 0) { puts("No solution"); return; }
    for (int i = 0; i < columns.size(); i++) {
        int r, c, v;
        decode(columns[i], r, c, v);
        Matrix[r][c] = v+1;
    }
    for (int r = 0; r < 9; r++) {
        for (int c = 0; c < 9; c++) {
            printf("%d", Matrix[r][c]);
        }
        puts("");
    }
}

int main() {
    #ifdef Phantom01
        freopen("HDU4069.txt", "r", stdin);
//        freopen("HDU4069.out", "w", stdout);
    #endif //Phantom01

    int T;
    scanf("%d", &T);
    for (int C = 1; C <= T; C++) {
        printf("Case %d:\n", C);
        for (int i = 0; i < 9; i++)
            for (int j = 0; j < 9; j++)
                scanf("%d", &Matrix[i][j]);

        for (int r = 0; r < 9; r++)
            for (int c = 0; c < 9; c++)
                belong[r][c] = -1;

        cnt = 0;
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) if (belong[r][c]==-1){
                dfs(r, c, 1);
                cnt++;
            }
        }
        solve();
    }

    return 0;
}

时间: 2024-10-11 13:24:43

HDU 4069 数独的相关文章

HDU 3909 数独

Sudoku Time Limit: 50000/20000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others) Total Submission(s): 501    Accepted Submission(s): 208 Problem Description AmazingCaddy likes Sudoku very much. One day, he got some Sudoku problems and he

Sudoku Killer(hdu 1426 数独)

数独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字.同时还要保证,空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字.比如有这样一个题,大家可以仔细观察一下,在这里面每行.每列,以及每个3x3的方格都包含1-9这九个数字. 例题: 答案: Input 本题包含多组测试,每组之间由一个空行隔开.每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开.其中1-9代表该位置的已经填好的数,问号(?

HDU 4069 Squiggly Sudoku Dancing-Links(DLX)+Floodfill

题目大意:..还是数独,不同的是原先的九宫格约束条件变为了给定的任意形状... 我们跑一遍floodfill 得出每一个格子属于哪一个形状 然后就是裸的数独了 这题T<=2500 绝对不能开动态 清则TLE 不清MLE 只能数组模拟 好不容易改完了 尼玛 交上去就WA 最后发现当找到一组解之后 一定要把当前的数独转移到ANS数组中 否则就会被覆盖 导致输出时错误 #include<cstdio> #include<cstring> #include<iostream&g

[DLX+bfs] hdu 4069 Squiggly Sudoku

题意: 给你9*9的矩阵.对于每个数字,能减16代表上面有墙,能减32代表下面有墙... 最后剩下的数字是0代表这个位置数要求,不是0代表这个数已知了. 然后通过墙会被数字分成9块. 然后做数独,这里的数独不是分成9个3*3的小块而是通过墙分成的. 思路: 首先通过数字作出墙. 然后bfs求连通块,dfs也可以.目的是分块. 然后就是dlx数独模板题了. 这里要注意的是如果找到答案2次就说明有多组解了,就应该停止返回了.不然会TLE. 代码: #include"stdio.h" #in

(中等) HDU 4069 Squiggly Sudoku , DLX+精确覆盖。

Description Today we play a squiggly sudoku, The objective is to fill a 9*9 grid with digits so that each column, each row, and each of the nine Connecting-sub-grids that compose the grid contains all of the digits from 1 to 9. Left figure is the puz

hdu 4069 福州赛区网络赛I DLC ***

再遇到一个DLC就刷个专题 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string> 10 #in

HDU 1426(数独 DFS)

题意是完成数独. 记录全图,将待填位置处填 0,记录下所有的待填位置,初始化结束.在每个待填位置处尝试填入 1 - 9,若经过判断后该位置可以填入某数字,则继续向下填下一个位置, 回溯时把待填位置重新赋值为 0,总之就是深搜的思想. 要注意存数时是从 0 位置存到 8 位置,而不是从 1 位置存到 9 位置,因为这样在后面判断是否满足 3*3 的小九宫格要求时可以直接用坐标乘以 3 再除以 3 的方法到达小九 宫格的左上角位置,便于遍历小九宫格. 代码如下: 1 #include <bits/s

hdu 4069 舞蹈链

#include <cstdio> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <cstring> #include <queue> using namespace std; const int maxn = 2096; const int maxnode = 10000; int wa[4] = {1

HDU 4069 Squiggly Sudoku【舞蹈链】【样例坑】

建模思路跟之前的一样,宫的话dfs搜索一下找联通分量就行,好像也没有更好的办法,有的话请评论哈orz --因为舞蹈链一般找到解以后就直接跳出了,所以ans数组就是ans不会再变.但这题让找一下有没有多组解,所以就不能找到一个解后直接跳出.就有一个小坑是都搜完后ans数组可能不是合法ans,所以找到第一个解的时候要单独存一下才能ac --但这个样例就是如果中间不存一下ans数组的话,样例还是能过... --那应该就是正好最后一次枚举的时候找到了这个解?? --不然的话它回溯的时候枚举下一个可能会覆