POJ 3074 Sudoku 【DLX】

题目来源:http://poj.org/problem?id=3074
在这里插入图片描述
★我是真滴菜,这题又搞了三天,最后又是一个小细节问题。但愿这次之后真正理解了舞蹈链


题意:

有一个9x9的矩阵,有些位置的数字已经确定了下来,但还有很多地方没确定。现在你要找到一个满足如下条件的填数字的方法,然后输入最终填完的矩阵
①:每个单元有且仅有一个数字
②:每一列包含了1-9的9个数字
③:每一行包含了1-9的9个数字
④:将矩阵划分为9块,每一块都包含了1-9的9个数字


思路:

这题可以用 舞蹈链求精确覆盖由于模板题在HUSTOJ上但是不能提交了,我也没写过模板题,导致卡了三天,不过现在大概是清楚了

先把模型转化成舞蹈链

题目给了4个约束条件,我们可以顺藤摸瓜,将约束条件转化成列,根据题意很容易知道,必须 找到一系列的行使得 所有的列上都有且仅有一个1 那么那些行就是答案了
约束条件①:( x , y )单元被填过了 代表第p1列
int p1=(x-1)*9+y;
约束条件②:第x行有一个数字v 代表第p2列
int p2=(x-1)*9+v+81;
约束条件③:第y列有一个数字v 代表第p3列
int p3=(y-1)*9+v+81*2;
约束条件④:第tmp块有一个数字v 代表第p4列
int tmp=((x-1)/3)*3+(y-1)/3+1; int p4=(tmp-1)*9+v+81*3;

至于行,就是每一个单元放什么数字咯~

得出答案

我们dance之后会得到很多行,但是这些行并不能直接得到题目要求的答案
我们不妨保存一个get数组记录每一行代表的意义(坐标以及数字),然后就好解决了


代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int N=81*9*4+81*4+10;
const int M=81*4+10;
const int inf=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
template<class T>
void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
struct DLX
{
    int n,m,cnt;
    int up[N],down[N],left[N],right[N],col[N];
    int sz[M],head[M<<1],get[N][3],ans[100];
    void init(int nn,int mm)
    {
        n=nn; m=mm;
        for(int i=0;i<=m;i++){
            up[i]=down[i]=i;
            right[i]=i+1;
            left[i]=i-1;
        }
        right[m]=0; left[0]=m;
        cnt=m;
        memset(head,-1,sizeof head);
        memset(sz,0,sizeof sz);
    }
    void link(int r,int c,int x,int y,int v)
    {
        cnt++;
        col[cnt]=c;
        sz[c]++;
        up[cnt]=up[c];
        down[cnt]=c;
        down[up[c]]=cnt;
        up[c]=cnt;
        get[cnt][0]=x; get[cnt][1]=y; get[cnt][2]=v;
        if(head[r]==-1) head[r]=right[cnt]=left[cnt]=cnt;
        else{
            int tmp=head[r];
            right[cnt]=tmp;
            left[cnt]=left[tmp];
            right[left[tmp]]=cnt;
            left[tmp]=cnt;
        }
    }
    void del(int c)
    {
        right[left[c]]=right[c];
        left[right[c]]=left[c];
        for(int i=down[c];i!=c;i=down[i]){
            for(int j=right[i];j!=i;j=right[j]){
                up[down[j]]=up[j];
                down[up[j]]=down[j];
                sz[col[j]]--;
            }
        }
    }
    void res(int c)
    {
        right[left[c]]=left[right[c]]=c;
        for(int i=down[c];i!=c;i=down[i]){
            for(int j=right[i];j!=i;j=right[j]){
                up[down[j]]=down[up[j]]=j;
                sz[col[j]]++;
            }
        }
    }
    bool dance(int dep)
    {
//        cout<<dep<<endl;
        if(dep==81) return 1;
        if(right[0]==0) return 0;
        int now=right[0];
        for(int i=now;i!=0;i=right[i]){
            if(sz[i]<sz[now]) now=i;
        }
        del(now);
        for(int i=down[now];i!=now;i=down[i]){
            ans[dep]=i;
            for(int j=right[i];j!=i;j=right[j]) del(col[j]);
            if(dance(dep+1)) return 1;
            for(int j=left[i];j!=i;j=left[j]) res(col[j]);
        }
        res(now);
        return 0;
    }
}dlx;
char s[100];
void hhh(int v,int x,int y,int &d)
{
    d++;
    int p1=(x-1)*9+y; //这个点放过没
    int p2=(x-1)*9+v+81; //这个行放过几
    int p3=(y-1)*9+v+81*2; //这个列放过几
    int tmp=((x-1)/3)*3+(y-1)/3+1;  //在第几块
    int p4=(tmp-1)*9+v+81*3;   //这一块放过几
//    cout<<d<<' '<<p1<<' '<<p2<<' '<<p3<<' '<<p4<<endl;
    dlx.link(d,p1,x,y,v);
    dlx.link(d,p2,x,y,v);
    dlx.link(d,p3,x,y,v);
    dlx.link(d,p4,x,y,v);
}
int main()
{
    while(~scanf("%s",s)){
        if(s[0]=='e') break;
        dlx.init(81*9,81*4);
        int r=0;
        for(int i=0;i<81;i++){

            int x=i/9+1;
            int y=i%9+1;
            if(s[i]=='.'){
                for(int i=1;i<=9;i++){
                    hhh(i,x,y,r);
                }
            }
            else hhh(s[i]-'0',x,y,r);
        }

        dlx.dance(0);
        int ans[10][10];
        for(int i=0;i<81;i++){
            int k=dlx.ans[i];
            ans[dlx.get[k][0]][dlx.get[k][1]]=dlx.get[k][2];
        }
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                printf("%d",ans[i][j]);
            }
        }
        printf("\n");
    }
}

发布了71 篇原创文章 · 获赞 89 · 访问量 8540

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/102855632