hdu4210 Sudominoku (dfs)

题意:数独游戏,不过只能用给定的多米诺骨牌填数独,而且每一个牌只能用一次,有唯一解

分析:对一个未填的方格枚举三十六个牌,每一个牌有俩种摆放方式,……

关键在于有没有好一点的判断方法,判断当前的放置方法是否符合数独的要求

用三个数字st[3][9]表示st[0]数组表示九行的放置状态,比如,st[0][0]的每一个位表示第一行对应选了哪一个数字

以此类推,st[1]表示列,st[2]表示3*3的方格

代码有点冗长了,好挫…………

View Code
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N = 10;
struct Domino
{
    int x,y;
}d[40];//保存所有的牌
struct Uncover
{
    int x,y;
}u[N*N];//保存未填的方格
int map[N][N],st[3][9],t,num;
//st[0]行,st[1]列,st[2]方格
int dir[2][2]={{0,1},{1,0}};
bool vis[N][N],flag;
//vis用来标记选了哪些牌
void init()
{
    for(int i=1;i<=8;i++)
        for(int j=i+1;j<=9;j++)
        {
            d[t].x=i,d[t].y=j;
            t++;
        }
}
bool isfinish()//判断数独是否填完整
{
    for(int i=0;i<3;i++)
        for(int j=0;j<9;j++)
            if(st[i][j]!=((1<<9)-1))
                return false;
    return true;
}
bool check(int x,int y,int xx,int yy,int first,int second)//判断该放置是否符合要求,是则修改对应的行列等的状态
{
    int ss1=(x/3)*3+y/3,ss2=(xx/3)*3+yy/3;
    first--,second--;
    if((st[0][x]&(1<<first))||(st[0][xx]&(1<<second)))
        return false;
    if((st[1][y]&(1<<first))||(st[1][yy]&(1<<second)))
        return false;
    if((st[2][ss1]&(1<<first))||(st[2][ss2]&(1<<second)))
        return false;
    st[0][x]|=(1<<first),st[0][xx]|=(1<<second);
    st[1][y]|=(1<<first),st[1][yy]|=(1<<second);
    st[2][ss1]|=(1<<first),st[2][ss2]|=(1<<second);
    return true;
}
void restore(int x,int y,int xx,int yy,int first,int second)//还原行列等的状态
{
    int ss1=(x/3)*3+y/3,ss2=(xx/3)*3+yy/3;
    first--,second--;
    st[0][x]&=~(1<<first),st[0][xx]&=~(1<<second);
    st[1][y]&=~(1<<first),st[1][yy]&=~(1<<second);
    st[2][ss1]&=~(1<<first),st[2][ss2]&=~(1<<second);
}
void set(int x,int y,int a)
{
    int ss=(x/3)*3+y/3;
    a--;
    st[0][x]|=(1<<a);
    st[1][y]|=(1<<a);
    st[2][ss]|=(1<<a);
}
void dfs(int n)
{
    int x=u[n].x,y=u[n].y;
    if(isfinish())
    {
        flag=true;
        return ;
    }
    for(int i=0;i<t;i++)//枚举骨牌
    {    
        if(vis[d[i].x][d[i].y])
            continue;
        vis[d[i].x][d[i].y]=true;
        for(int f=0;f<2;f++)//骨牌正反放置
        {
            int first=d[i].x,second=d[i].y;
            if(f&1) swap(first,second);
            for(int k=0;k<2;k++)//放置的方向
            {    
                int temp=n;
                int xx=x+dir[k][0];
                int yy=y+dir[k][1];
                if(xx<0 || xx>=9 || yy<0 || yy>=9 || map[xx][yy]!=0)
                    continue;
                if(!check(x,y,xx,yy,first,second))
                    continue;
                map[x][y]=first,map[xx][yy]=second;
                if(map[u[temp+1].x][u[temp+1].y]==0)
                    dfs(temp+1);
                else {
                    while(temp<num && map[u[temp+1].x][u[temp+1].y]!=0)//已经填上的方格跳过
                        temp++;
                    dfs(temp+1);
                }
                if(flag) return;
                restore(x,y,xx,yy,first,second);
                map[x][y]=0,map[xx][yy]=0;
            }
        }
        vis[d[i].x][d[i].y]=false;
    }            
}
int main()
{
    t=0;
    init();
    int m,cas=0;
    char s1[5],s2[5];
    int a,b,c,d;
    while(scanf("%d",&m)==1 && m)
    {
        memset(vis,false,sizeof(vis));
        memset(map,0,sizeof(map));
        memset(st,0,sizeof(st));
        for(int i=0;i<m;i++)
        {
            scanf("%d %s %d %s",&a,s1,&b,s2);
            int x=s1[0]-'A',y=s1[1]-'0'-1;
            map[x][y]=a;
            set(x,y,a);
            x=s2[0]-'A',y=s2[1]-'0'-1;
            map[x][y]=b;
            set(x,y,b);
            vis[a][b]=vis[b][a]=true;
        }
        for(int i=1;i<=9;i++)
        {
            scanf("%s",s1);
            int x=s1[0]-'A',y=s1[1]-'0'-1;
            set(x,y,i);
            map[x][y]=i;
        }
        num=0;
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                if(map[i][j]==0)
                {
                    u[num].x=i,u[num].y=j;
                    num++;
                }
        flag=false;
        dfs(0);
        printf("Puzzle %d\n",++cas);
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
                printf("%d",map[i][j]);
            puts("");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2440645.html