• 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;
    }
  • 相关阅读:
    搜索栏+collectionView实现
    iOS密码框实现(二)取消确定按钮
    MotionManager 陀螺仪实现方式
    ubuntu常用命令
    Ubuntu 启用root账户
    How to solve “sudo: /etc/sudoers.d is world writable”
    ubuntu進入dos界面的方法
    炫耀一下hadoop學習成果
    fpdf使用標楷體
    win8磁盘占用100%的12种解决办法
  • 原文地址:https://www.cnblogs.com/nanke/p/2440645.html
Copyright © 2020-2023  润新知