zoukankan      html  css  js  c++  java
  • hdu3111 Sudoku (精确覆盖解数独 DLX)

     精确覆盖:

        首先选择当前要覆盖的列(含1最少的列),将该列和能够覆盖到该列的行全部去掉,再枚举添加的方法。枚举某一行r,假设它是解集中的一个,那么该行所能覆盖到的所有列都不必再搜,所以删除该行覆盖到的所有列,又由于去掉的列相当于有解,所以能够覆盖到这些列的行也不用再搜,删之。

    View Code
    /*
    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;
    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]++;
    now = i*n+j;
    C[now] = j;
    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]);
    printf("\n");
    }
    }
    if(T!=0)
    printf("---\n");
    }

    int main()
    {
    int i,j,k;
    int cases;
    char cao[12];
    char s[12][12];
    scanf("%d",&cases);
    T = cases;
    while(T--)
    {
    if(T < cases-1)
    scanf("%s",cao);
    for(i = 1; i <= 9; i++)
    scanf("%s",&s[i][1]);
    memset(mx,0,sizeof(mx));
    for(i = 1; i <= 9; i++)
    {
    for(j = 1; j <= 9; j++)
    {
    int t = (i-1)*9 + j;
    if(s[i][j] == '?')
    {
    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 = s[i][j] - '0';
    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;
    }

     以上参考此博客http://yzmduncan.iteye.com/blog/1151695

  • 相关阅读:
    C#处理json实战
    HDU3994(Folyd + 期望概率)
    POJ1270 Following Orders (拓扑排序)
    HDU 3634 City Planning (离散化)
    HDU4762(JAVA大数)
    POJ3026(BFS + prim)
    POJ1679(次小生成树)
    UVA10487(二分)
    ZOJ 2048(Prim 或者 Kruskal)
    FZU 1856 The Troop (JAVA高精度)
  • 原文地址:https://www.cnblogs.com/nanke/p/2363668.html
Copyright © 2011-2022 走看看