Dancing Links---- F - Squiggly Sudoku

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 puzzle and right figure is one solution.

在这里插入图片描述
Now, give you the information of the puzzle, please tell me is there no solution or multiple solution or one solution.
Input
The first line is a number T(1<=T<=2500), represents the number of case. The next T blocks follow each indicates a case.
Each case contains nine lines, Each line contains nine integers.
Each module number tells the information of the gird and is the sum of up to five integers:
0~9: ‘0’ means this gird is empty, ‘1’ - ‘9’ means the gird is already filled in.
16: wall to the up
32: wall to the right
64: wall to the down
128: wall to the left
I promise there must be nine Connecting-sub-grids, and each contains nine girds.
Output
For each case, if there are Multiple Solutions or no solution just output “Multiple Solutions” or “No solution”. Else output the exclusive solution.(as shown in the sample output)
Sample Input
3
144 18 112 208 80 25 54 144 48
135 38 147 80 121 128 97 130 32
137 32 160 144 114 167 208 0 32
192 100 160 160 208 96 183 192 101
209 80 39 192 86 48 136 80 114
152 48 226 144 112 160 160 149 48
128 0 112 166 215 96 160 128 41
128 39 153 32 209 80 101 136 35
192 96 200 67 80 112 208 68 96

144 48 144 81 81 16 53 144 48
128 96 224 144 48 128 103 128 38
163 208 80 0 37 224 209 0 32
135 48 176 192 64 112 176 192 104
192 101 128 89 80 82 32 150 48
149 48 224 208 16 48 224 192 33
128 0 114 176 135 0 80 112 169
137 32 148 32 192 96 176 144 32
192 96 193 64 80 80 96 192 96

144 88 48 217 16 16 80 112 176
224 176 129 48 128 40 208 16 37
145 32 128 96 196 96 176 136 32
192 32 227 176 144 80 96 192 32
176 192 80 98 160 145 80 48 224
128 48 144 80 96 224 183 128 48
128 36 224 144 51 144 32 128 105
131 64 112 136 32 192 36 224 176
224 208 80 64 64 116 192 83 96
Sample Output
Case 1:
521439678
763895124
984527361
346182795
157964832
812743956
235678419
479216583
698351247
Case 2:
No solution
Case 3:
Multiple Solutions

这道题就是dfs找联通块,原先做的那个数独题是要求每一宫要求1~9的数,现在这个题是每一行,每一列和每一个联通块,其实都是一样的。。。。
我wa的原因是:由于有多种解法,dlx搜索的时候,找到一个解法的时候应该把这个解法存下来,要不然就被找下一个解法的时候就覆盖了
题中每个数都代表在该点可走的方向,一共有15个数,分别是0,16,32,64,128,48,80,144,96,160,192,112,176,224,208。。。。
举个例子,像80就有两个方向可走,左和右

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double PI = acos(-1);
#define pb push_back
#define mp make_pair
#define fi first
#define se second

//最大行数
const int MN = 4100;
//最大列数
const int MM = 1100;
//最大点数
const int MNN = 16 * 16 * 16 * 4 + 100;

struct DLX
{
    //一共n行m列,s个节点
    int n,m,s;
    //交叉十字链表组成部分
    //第i个节点的上U下D左L右R,所在位置row行col列
    int U[MNN],D[MNN],L[MNN],R[MNN],row[MNN],col[MNN];
    //H数组记录行选择指针,S数组记录覆盖个数
    int H[MN],S[MM];
    //res记录行个数,ans数组记录可行解
    int res,ans[MN],flag,mm[MN];
    //初始化空表
    void init(int x,int y)
    {
        n = x,m = y;
        //其中0节点作为head节点,其他作为列首节点
        for(int i = 0;i <= m;++i){
            U[i] = D[i] = i;
            L[i] = i - 1;
            R[i] = i + 1;
        }
        R[m] = 0;L[0] = m;
        s = m;
        memset(S,0,sizeof(S));
        memset(H,-1,sizeof(H));
    }
    void Insert(int r,int c)
    {
        //cout << c << endl;
        //节点数加一,设置s节点所处位置,以及S列覆盖个数加一
        s++;row[s] = r;col[s] = c;S[c]++;
        //将s节点插入对应列中
        D[s] = D[c];U[D[c]] = s;
        U[s] = c;D[c] = s;
        if(H[r] < 0){//如果该行没有元素,H[r]标记该行起始节点
            H[r] = L[s] = R[s] = s;
        }else{
            //将该节点插入该行第一个节点后面
            R[s] = R[H[r]];
            L[R[H[r]]] = s;
            L[s] = H[r];
            R[H[r]] = s;
        }
    }
    //精确覆盖
    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]){//枚举该列元素
            for(int j = R[i];j != i;j = R[j]){//枚举列的某个元素所在行遍历
                U[D[j]] = U[j];
                D[U[j]] = D[j];
                //将该列上的S数组减一
                --S[col[j]];
            }
        }
    }
    void resume(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;
    }
    void dance(int deep)
    {
        if(flag > 1) return ;
        //当矩阵为空时,说明找到一个可行解,算法终止
       // cout << "R:" << R[0] << endl;
        if(R[0] == 0){
            memcpy(mm,ans,sizeof(ans));
            res = deep;
            flag++;
            return ;
        }
        //找到节点数最少的列,枚举这列上的所有行
        int c = R[0];
        for(int i = R[0];i != 0;i = R[i]){
            if(S[i] < S[c]){
                c = i;
            }
        }
        //cout << c << endl;
        //删除节点数最少的列
        Remove(c);
        for(int i = D[c];i != c;i = D[i]){
            //将行r放入当前解
            ans[deep] = row[i];
            //行上节点对应的列上进行删除
            for(int j = R[i];j != i;j = R[j])
                Remove(col[j]);
            //进入下一层
            dance(deep + 1);
            //对行上的节点对应的列进行恢复
            for(int j = L[i];j != i;j = L[j])
                resume(col[j]);
        }
        //恢复节点数最少列
        resume(c);
    }

    //重复覆盖
    //将列与矩阵完全分开
    void Remove1(int c)
    {
        for(int i = D[c];i != c;i = D[i]){
            L[R[i]] = L[i];
            R[L[i]] = R[i];
        }
    }
    void resume1(int c)
    {
        for(int i = D[c];i != c;i = D[i]){
            L[R[i]] = R[L[i]] = i;
        }
    }
    int vis[MNN];
    //估价函数,模拟删除列,H(),函数返回的是至少还需要多少行才能完成重复覆盖
    int A()
    {
        int dis = 0;
        for(int i = R[0];i != 0;i = R[i]) vis[i] = 0;
        for(int i = R[0];i != 0;i = R[i]){
            if(!vis[i]){
                dis++;vis[i] = 1;
                for(int j = D[i];j != i;j = D[j]){
                    for(int k = R[j];k != j;k = R[k]){
                        vis[col[k]] = 1;
                    }
                }
            }
        }
        return dis;
    }

    void dfs(int deep)
    {
        if(res > 1) return ;
        if(!R[0]){
            res++;
            return;
        }
        int c = R[0];
        for(int i = R[0];i != 0;i = R[i]){
            if(S[i] < S[c]){
                c = i;
            }
        }
        for(int i = D[c];i != c;i = D[i]){
            //每次将第i列其他节点删除,只保留第i节点,为了找该行的节点
            Remove1(i);
            //将列上的节点完全与矩阵脱离,只删列首节点是不行的
            for(int j = R[i];j != i;j = R[j]){
                Remove1(j);
            }
            dfs(deep + 1);
            for(int j = L[i];j != i;j = L[j]){
                resume1(j);
            }
            resume1(i);
        }
    }
}dlx;

const int N = 15;
int col[5] = {-1,1,0,0};
int con[5] = {0,0,-1,1};
bool vis[N][N];
int a[N][N];
int b[N][N];
int c[N][N];
int cnt = 0;
int ans[17] = {0,16,32,64,128,48,80,144,96,160,192,112,176,224,208};
map<int,vector<int> >mk;
pair<pair<int,int>,int>ve[1005];

void dfs(int x,int y)
{
    if(vis[x][y]) return ;
    vis[x][y] = true;
    for(int i = 0;i < 15;++i){
        int tmp = a[x][y] - ans[i];
        if(tmp >= 0 && tmp <= 9){
            b[x][y] = tmp;
            c[x][y] = cnt;
            int len = mk[ans[i]].size();
            for(int j = 0;j < len;++j){
                int x1 = x + col[mk[ans[i]][j]],y1 = y + con[mk[ans[i]][j]];
                if(x1 < 0 || y1 < 0 || x1 >= 9 || y1 >= 9 || vis[x1][y1]) continue;
                dfs(x1,y1);
            }
            break;
        }
    }
}

void init()
{
    dlx.init(729,4 * 81);
    int k = 1;
    for(int i = 0;i < 9;++i){
        for(int j = 0;j < 9;++j){
            if(b[i][j]){
                dlx.Insert(k,i * 9 + j + 1);
                dlx.Insert(k,81 + i * 9 + b[i][j]);
                dlx.Insert(k,2 * 81 + 9 * j + b[i][j]);
                dlx.Insert(k,3 * 81 + 9 * c[i][j] + b[i][j]);
                ve[k].fi = mp(i,j);ve[k].se = b[i][j];
                k++;
            }else{
                for(int x = 1;x <= 9;++x){
                    dlx.Insert(k,i * 9 + j + 1);
                    dlx.Insert(k,81 + i * 9 + x);
                    dlx.Insert(k,2 * 81 + 9 * j + x);
                    dlx.Insert(k,3 * 81 + 9 * c[i][j] + x);
                    ve[k].fi = mp(i,j);ve[k].se = x;
                    k++;
                }
            }
        }
    }
    dlx.flag = dlx.res = 0;
    dlx.dance(0);
    if(dlx.flag == 0){
        printf("No solution\n");
    }else  if(dlx.flag > 1){
        printf("Multiple Solutions\n");
    }else{
        for(int i = 0;i < dlx.res;++i){
            b[ve[dlx.mm[i]].fi.fi][ve[dlx.mm[i]].fi.se] = ve[dlx.mm[i]].se;
        }
        for(int i = 0;i < 9;++i){
            for(int j = 0;j < 9;++j){
                printf("%d",b[i][j]);
            }
            printf("\n");
        }
    }
}

int main()
{
    int t;
    mk[0].pb(0);mk[0].pb(1);mk[0].pb(2);mk[0].pb(3);
    mk[16].pb(2);mk[16].pb(1);mk[16].pb(3);
    mk[32].pb(0);mk[32].pb(1);mk[32].pb(2);
    mk[64].pb(0);mk[64].pb(2);mk[64].pb(3);
    mk[128].pb(0);mk[128].pb(1);mk[128].pb(3);
    mk[48].pb(1);mk[48].pb(2);
    mk[80].pb(2);mk[80].pb(3);
    mk[144].pb(1);mk[144].pb(3);
    mk[96].pb(0);mk[96].pb(2);
    mk[160].pb(0);mk[160].pb(1);
    mk[192].pb(0);mk[192].pb(3);
    mk[112].pb(2);mk[176].pb(1);mk[224].pb(0);mk[208].pb(3);
    scanf("%d",&t);
    int p = 0;
    while(t--)
    {
        p++;
        memset(vis,false,sizeof(vis));
        for(int i = 0;i < 9;++i){
            for(int j = 0;j < 9;++j){
                scanf("%d",&a[i][j]);
            }
        }
        cnt = 0;
        for(int i = 0;i < 9;++i){
            for(int j = 0;j < 9;++j){
                if(!vis[i][j]){
                    dfs(i,j);
                    cnt++;
                }
            }
        }
        printf("Case %d:\n",p);
        init();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/82930585