HDU 4069 Squiggly Sudoku 【DLX+BFS】

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4069
在這裏插入圖片描述
在這裏插入圖片描述
★這題一開始題都看不懂,後來發現還是挺有意思的


題意:

給你一個9x9的矩陣, 矩陣裏面有一些牆將數字劃分爲9個包含9個數字的宮 ,現在要問你能不能找到一種填數字的辦法,使得矩陣的 每一行 每一列 每一宮 都包含9個不同的數字
而輸入告訴你每個點的哪個方向有牆,輸入中的81個數代表的意思是這樣的:
如果這個數所在的單元沒有牆,那這個數就是它本身,否則左邊有牆就加128,下面有加64,右邊有加32,上面有加16 比如第一個數144=128+16 故它所在的地方上面和左邊有牆,而第二個數18=16+2即上面有牆值爲2


思路:

玩過一般的數獨,就是給一個9x9的矩陣,你要往裏面填數字,必須滿足哪些行、列包含1至9的所有數字。
但這題加了點難度,我寫的上一題是劃分爲9個小3*3的方陣,這題是9個形狀變化的宮
但其實也還好,我們只要先找到那些單元在哪些宮就好了。這裏通過BFS解決,DFS好像也可以吧

BFS

廣搜前先記錄下哪些單元的哪些方向有牆,有牆當然不走那個方向。然後就基本上是普通的BFS了。

void bfs(int x,int y,int c) //x y即座標 c就是所在的宮id   從1到9
{
    queue<point> q;
    vis[x][y]=1;
    p[x][y].plc=c;        
    point now=p[x][y];
    q.push(now);
    while(q.size()){
        now=q.front();
        q.pop();              
        for(int i=0;i<4;i++){   //四個方向
            if(!now.d[i]){      //沒牆可走
                int xx=now.x+D[i][0];   
                int yy=now.y+D[i][1];
                if(!vis[xx][yy]){       //沒被標記過 
                    vis[xx][yy]=1;
                    p[xx][yy].plc=c;
                    q.push(p[xx][yy]);
                }
            }
        }
    }
}
DLX

然後剩下的基本是DLX求數獨的老套路了,以每個點放什麼數爲行 最多81x9行 ,以每個點放了沒(1-81)、每一行放了什麼數(82-162)、每一列放了什麼數(163-243)、每一宮放了什麼數(244-324)爲列
就是在dance的時候稍稍修改,判斷如果有兩個答案就直接return ;


代碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int N=81*9*81*4+5;
const int M=81*9+5;
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;
}
int D[4][2]={{0,-1},{1,0},{0,1},{-1,0}}; //left down right up
struct DLX
{
    int n,m,cnt,num;
    int up[N],right[N],left[N],down[N];
    int col[N],head[M],sz[M];
    int test[N],get[N][3],ans[N];
    void init(int nn,int mm)
    {
        n=nn; m=mm;
        num=0;
        for(int i=0;i<=m;i++){
            up[i]=down[i]=i;
            left[i]=i-1;
            right[i]=i+1;
            sz[i]=0;
        }
        cnt=m;
        left[0]=m; right[m]=0;
        for(int i=1;i<=n;i++) head[i]=-1;
    }
    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]=left[cnt]=right[cnt]=cnt;
        else{
            int tmp=head[r];
            right[cnt]=tmp;
            left[cnt]=left[tmp];
            right[left[tmp]]=cnt;
            left[tmp]=cnt;
        }
    }
    void Remove(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 Resume(int c)
    {
        right[left[c]]=left[right[c]]=c;
        for(int i=up[c];i!=c;i=up[i]){
            for(int j=right[i];j!=i;j=right[j]){
                up[down[j]]=down[up[j]]=j;
                sz[col[j]]++;
            }
        }
    }
    void dance(int dep)
    {
//        cout<<dep<<endl;
        if(right[0]==0&&dep==81){
            num++;
            for(int i=0;i<81;i++) ans[i]=test[i];
            return ;
        }
        if(right[0]==0||num>=2) return ;
        int now=right[0];
        for(int i=now;i!=0;i=right[i]){
            if(sz[i]<sz[now]) now=i;
        }
        Remove(now);
        for(int i=down[now];i!=now;i=down[i]){
            test[dep]=i;
            for(int j=right[i];j!=i;j=right[j]) Remove(col[j]);
            dance(dep+1);
            if(num>=2) return ;
            for(int j=left[i];j!=i;j=left[j]) Resume(col[j]);
        }
        Resume(now);
    }
}dlx;
struct point
{
    int x,y,plc,val;   //(x,y),place,value
    int d[4];      //direction
}p[10][10];
bool vis[10][10];
void bfs(int x,int y,int c)
{
    queue<point> q;
    vis[x][y]=1;
    p[x][y].plc=c;
    point now=p[x][y];
    q.push(now);
    while(q.size()){
        now=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            if(!now.d[i]){
                int xx=now.x+D[i][0];
                int yy=now.y+D[i][1];
                if(!vis[xx][yy]){
                    vis[xx][yy]=1;
                    p[xx][yy].plc=c;
                    q.push(p[xx][yy]);
                }
            }
        }
    }
}
void hhh(int x,int y,int v,int &s)
{
    s++;
    int p1=(x-1)*9+y;    //(x,y) 放過了
    int p2=(x-1)*9+v+81;    //x行放了數字v
    int p3=(y-1)*9+v+81*2;   //y列放了數字v
    int p4=(p[x][y].plc-1)*9+v+81*3;  //宮plc放過了數字v
    dlx.link(s,p1,x,y,v);
    dlx.link(s,p2,x,y,v);
    dlx.link(s,p3,x,y,v);
    dlx.link(s,p4,x,y,v);
}
int main()
{
    int t;
    read(t);
    int cas=0;
    while(t--){
        memset(p,0,sizeof p);
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                read(p[i][j].val);
                p[i][j].x=i; p[i][j].y=j;
                if(p[i][j].val>=128){ //there is a wall on left
                    p[i][j].val-=128;
                    p[i][j].d[0]=1;
                }
                if(p[i][j].val>=64){ //there is a wall on down
                    p[i][j].val-=64;
                    p[i][j].d[1]=1;
                }
                if(p[i][j].val>=32){ //there is a wall on right
                    p[i][j].val-=32;
                    p[i][j].d[2]=1;
                }
                if(p[i][j].val>=16){ //there is a wall on up
                    p[i][j].val-=16;
                    p[i][j].d[3]=1;
                }
            }
        }
        int cnt=0;
        memset(vis,0,sizeof vis);
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                if(!vis[i][j]){
                    bfs(i,j,++cnt);
                }
            }
        }
        cnt=0;
        int pp=0;
        dlx.init(81*9,81*4);
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                if(p[i][j].val==0){
                    pp++;
                    for(int k=1;k<=9;k++)
                        hhh(i,j,k,cnt);
                }
                else hhh(i,j,p[i][j].val,cnt);

            }
        }
        dlx.dance(0);
        printf("Case %d:\n",++cas);
        if(dlx.num==0) cout<<"No solution\n";
        else if(dlx.num==2) cout<<"Multiple Solutions\n";
        else{
            int res[10][10];
            for(int i=0;i<81;i++){
                int t=dlx.ans[i];
                int x=dlx.get[t][0];
                int y=dlx.get[t][1];
                int v=dlx.get[t][2];
                res[x][y]=v;
            }
            for(int i=1;i<=9;i++){
                for(int j=1;j<=9;j++){
                    cout<<res[i][j];
                }
                cout<<endl;
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章