數獨問題&模板


/*

DLX解決9*9的數獨問題,轉化爲729*324的精確覆蓋問題

行:

一共9 * 9 * 9 == 729行。一共9 * 9小格,每一格有9種可能性(1 - 9),每一種可能都對應着一行。

列:

一共(9 + 9 + 9) * 9 + 81 == 324 種前面三個9分別代表着9行9列和9小塊,乘以9的意思是9種可能(1 - 9),因爲每種可能只可以選擇一個。

81代表着81個小格,限制着每一個小格只放一個數字。

讀入數據後,如果爲'.',則建9行,即有1-9種可能,否則建一行,表示某小格只能放確定的某個數字。

*/

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int INF = 0x7fffffff;

const int NN = 350;

const int MM = 750;

#define N 9

int n,m;    //列,行

int cntc[NN];

int L[NN*MM],R[NN*MM],U[NN*MM],D[NN*MM];//節點的左邊,右邊,上邊,下邊

int C[NN*MM];

int head;

int mx[MM][NN];

int O[MM],idx;

int ans[10][10];



//刪除列及其相應的行

void remove(int c)

{

    int i,j;

    L[R[c]] = L[c];

    R[L[c]] = R[c];

    for(i = D[c]; i != c; i = D[i])

    {

        for(j = R[i]; j != i; j = R[j])

        {

            U[D[j]] = U[j];

            D[U[j]] = D[j];

            cntc[C[j]]--;

        }

    }

}



//恢復列及其相應的行

void resume(int c)

{

    int i,j;

    R[L[c]] = c;

    L[R[c]] = c;

    for(i = D[c]; i != c; i = D[i])

    {

        for(j = R[i]; j != i; j = R[j])

        {

            U[D[j]] = j;

            D[U[j]] = j;

            cntc[C[j]]++;

        }

    }

}



bool dfs()

{

    int i,j,c;

    if(R[head] == head)

        return true;

    int min = INF;

    for(i = R[head]; i != head; i = R[i])

    {

        if(cntc[i] < min)

        {

            min = cntc[i];

            c = i;

        }

    }

    remove(c);

    for(i = D[c]; i != c; i = D[i])

    {

        //i是某點的序號,將該點所在行的行號保存

        O[idx++] = (i-1)/n;

        for(j = R[i]; j != i; j = R[j])

            remove(C[j]);

        if(dfs())

            return true;

        for(j = L[i]; j != i; j = L[j])

            resume(C[j]);

        idx--;

    }

    resume(c);

    return false;

}



bool build()

{

    int i,j,now,pre,first;

    idx = head = 0;

    for(i = 0; i < n; i++)

    {

        R[i] = i+1;

        L[i+1] = i;

    }

    R[n] = 0;

    L[0] = n;

    //列雙向鏈表

    for(j = 1; j <= n; j++)

    {

        pre = j;

        cntc[j] = 0;

        for(i = 1; i <= m; i++)

        {

            if(mx[i][j])

            {

                cntc[j]++;//j的邊數

                now = i*n+j;

                C[now] = j;//C爲列指針

                D[pre] = now;

                U[now] = pre;

                pre = now;

            }

        }

        U[j] = pre;

        D[pre] = j;

        if(cntc[j] == 0)

            return false;

    }

    //行雙向鏈表

    for(i = 1; i <= m; i++)

    {

        pre = first = -1;

        for(j = 1; j <= n; j++)

        {

            if(mx[i][j])

            {

                now = i*n+j;

                if(pre == -1)

                    first = now;

                else

                {

                    R[pre] = now;

                    L[now] = pre;

                }

                pre = now;

            }

        }

        if(first != -1)

        {

            R[pre] = first;

            L[first] = pre;

        }

    }

    return true;

}



int T;



void print()

{

    int i,j;

    int x,y,k;

    for(i = 0; i < idx; i++)

    {

        int r = O[i];

        k = r%9;

        if(k==0) k = 9;

        int num = (r - k)/9 + 1;

        y = num%9;

        if(y == 0) y = 9;

        x = (num-y)/9 + 1;

        ans[x][y] = k;

    }

    if(idx == 0)

        printf("impossible\n");

    else

    {

        for(i = 1; i <= 9; i++)

        {

            for(j = 1; j <= 9; j++)

                printf("%d",ans[i][j]);

        }

        cout<<endl;

    }

}



int map[MM][NN];

string str;

void readdata()

{

    char ch;

    int ind=0;

    for(int i = 1; i <= N; i++)

        for(int j = 1; j <= N; j++)

          {

            ch=str[ind++];

            if(ch=='.')

            map[i][j]=0;

            else

            map[i][j]=ch-'0';

          }

}

int main()

{

    int i,j,k;

    int cases;

    char cao[12];

    char s[12][12];

    while(1)

    {

        cin>>str;

        if(str=="end")break;

        memset(mx,0,sizeof(mx));

        readdata();

        for(i = 1; i <= 9; i++)

        {

            for(j = 1; j <= 9; j++)

             {

                int t = (i-1)*9 + j;

                if(map[i][j] == 0)

                {

                    for(k = 1; k <= 9; k++)

                    {

                        mx[9*(t-1)+k][t] = 1;               //81grid 每個小格只能放一個數字

                        mx[9*(t-1)+k][81+(i-1)*9+k] = 1;    //9row 每行數字k只能出現一次

                        mx[9*(t-1)+k][162+(j-1)*9+k] = 1;   //9col  每列數字k只能出現一次

                        mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;   //subgrid 每個3*3格子數字k只能出現一次

                    }

                }

                else

                {

                    k = map[i][j];

                    mx[9*(t-1)+k][t] = 1;               //81grid

                    mx[9*(t-1)+k][81+(i-1)*9+k] = 1;    //9row

                    mx[9*(t-1)+k][162+(j-1)*9+k] = 1;   //9col

                    mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;   //subgrid

                }

            }

        }

        n = 324;

        m = 729;

        build();

        dfs();

        print();

    }

    return 0;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章