解数独算法

筅森魡賤 提交于 2019-12-10 19:19:14

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

完善填数解数独

#include<stdio.h>
#include<string.h>
struct Avaliable
{
    short row;
    short col;
};

int OnlyAvaliable(short n)
{
    return n!= 0 && ( n & ( n - 1 ) ) == 0;
}
int PointAvaliable(short n)
{
    return n?PointAvaliable(n & ( n - 1 ))+1:0;
}
int getHighBit(short n)
{
    int i = 0;
    while(n)
    {
        n/=2;
        i++;
    }
    return i-1;
}

Avaliable g_avas[9][9];
int g_solved = 0;
unsigned short g_SudokuMap[9][9] = {
        // {1,3,0,0,6,8,0,0,0},
        // {6,0,0,0,0,0,0,8,1},
        // {5,0,0,0,4,0,2,0,0},
        // {3,0,0,7,0,2,0,0,0},
        // {4,1,7,0,8,0,3,5,2},
        // {0,0,0,1,0,4,0,0,9},
        // {0,0,4,0,7,0,0,0,8},
        // {2,8,0,0,0,0,0,0,6},
        // {0,0,0,8,9,0,0,2,5},
//      需要填数
        {0,0,0,0,0,0,0,0,0},
        {0,0,2,3,0,5,9,0,0},
        {0,1,0,0,4,0,0,7,0},
        {0,7,0,0,0,9,0,6,0},
        {0,0,8,0,0,0,3,0,0},
        {0,4,0,5,0,0,0,2,0},
        {0,2,0,0,7,0,0,4,0},
        {0,0,9,8,0,3,2,0,0},
        {0,0,0,0,0,0,0,0,0},
//      困难
        // {0,0,0,0,4,0,2,0,0},
        // {0,1,0,0,0,6,0,0,9},
        // {0,0,5,0,0,0,0,0,7},
        // {0,0,0,9,0,7,0,0,6},
        // {0,0,0,0,5,0,0,0,0},
        // {2,0,0,8,0,3,0,0,0},
        // {3,0,0,0,0,0,6,0,0},
        // {4,0,0,2,0,0,0,8,0},
        // {0,0,9,0,1,0,0,0,0},
};


void SolveSudoku(unsigned short SudokuMap[9][9],Avaliable avas[9][9],int n)
{
    int i,j,k,l,temp,minava[3],result,count;
    unsigned short l_SudokuMap[9][9];
    Avaliable l_avas[9][9];
    while( n > 0 )
    {
        minava[0] = 10;
        minava[1] = -1;
        minava[2] = -1;
        for ( i = 0 ; i < 9 ; i++ )
        {
            for ( j  = 0 ; j < 9 ; j++ )
            {
                temp = SudokuMap[i][j];
                if ( temp == 0 )
                {
                    result = avas[i][j].row & avas[i][j].col;
                    if ( OnlyAvaliable( result ) )
                    {
                        temp = getHighBit(result);
                        for( k = 0 ; k < 9 ; k++ )
                        {
                            avas[i][k].col &= ~( 1 << temp );
                            avas[k][j].row &= ~( 1 << temp );
                            avas[i/3*3+k/3][j/3*3+k%3].col &= ~( 1 << temp );
                            avas[i/3*3+k/3][j/3*3+k%3].row &= ~( 1 << temp );
                        }
                        avas[i][j].row = avas[i][j].col = 0;
                        SudokuMap[i][j] = temp;
                        n --;
                    }
                }
            }
        }
        for ( i = 0 ; i < 9 ; i++ )
        {
            for ( j  = 0 ; j < 9 ; j++ )
            {
                temp = SudokuMap[i][j];
                if ( temp == 0 )
                {
                    result = avas[i][j].row & avas[i][j].col;
                    temp = PointAvaliable(result);
                    if( 0 < temp && temp < minava[0]  )
                    {
                        minava[0] = temp;
                        minava[1] = i;
                        minava[2] = j;
                    }
                }
            }
        }
        if( 1 < minava[0]  && minava[0] < 10 )
        {
            i = minava[1];
            j = minava[2];
            l = avas[i][j].row & avas[i][j].col;
            temp = 1;
            count = 0;
            memcpy(l_SudokuMap,SudokuMap,sizeof(l_SudokuMap));
            memcpy(l_avas,avas,sizeof(l_avas));
            while( l > temp )
            {
                count++;
                temp <<= 1;
                if( l & temp )
                {
                    l_SudokuMap[i][j] = count;
                    for( k = 0 ; k < 9 ; k++ )
                    {
                        l_avas[i][k].col &= ~temp;
                        l_avas[k][j].row &= ~temp;
                        l_avas[i/3*3+k/3][j/3*3+k%3].col &= ~temp;
                        l_avas[i/3*3+k/3][j/3*3+k%3].row &= ~temp;
                    }
                    l_avas[i][j].row = l_avas[i][j].col = 0;
                    SolveSudoku( l_SudokuMap,l_avas,n - 1 );
                    if(g_solved)
                    {
                        return;
                    }
                    else
                    {
                        l_SudokuMap[i][j] = 0;
                        for( k = 0 ; k < 9 ; k++ )
                        {
                            l_avas[i][k].col |= temp;
                            l_avas[k][j].row |= temp;
                            l_avas[i/3*3+k/3][j/3*3+k%3].col |= temp;
                            l_avas[i/3*3+k/3][j/3*3+k%3].row |= temp;
                        }
                        l_avas[i][j].row = avas[i][j].row;
                        l_avas[i][j].col = avas[i][j].col;
                    }
                }
            }
            //既然到了填数的阶段了,说明前面填数除了冲突,可以回溯。
            return ;
        }
        else if( minava[0] == 10 && n != 0)
        {
            return;
        }
        //因为n--在内部,所以可能出现了填好的状态。
    }
    memcpy(g_SudokuMap,SudokuMap,sizeof(g_SudokuMap));
    g_solved = 1;
}

int main()
{
    Avaliable (*avas)[9]=g_avas;
    unsigned short (*SudokuMap)[9]=g_SudokuMap;

    int i,j,k,temp,unsolved = 81;
    for ( k = ( 1 << 10 ) - 2, i = 0 ; i < 9 ; i++ )
    {
        for ( j  = 0 ; j < 9 ; j++ )
        {
            avas[i][j].row = avas[i][j].col = k;
        }
    }
    for ( i = 0 ; i < 9 ; i++ )
    {
        for ( j  = 0 ; j < 9 ; j++ )
        {
            temp = SudokuMap[i][j];
            if( temp != 0 )
            {
                for( k = 0 ; k < 9 ; k++ )
                {
                    avas[i][k].col &= ~( 1 << temp );
                    avas[k][j].row &= ~( 1 << temp );
                    avas[i/3*3+k/3][j/3*3+k%3].col &= ~( 1 << temp );
                    avas[i/3*3+k/3][j/3*3+k%3].row &= ~( 1 << temp );
                }
                avas[i][j].row = avas[i][j].col = 0;
                unsolved --;
            }
        }
    }
    SolveSudoku(SudokuMap,avas,unsolved);
    for ( i = 0 ; i < 9 ; i++ )
    {
        for ( j  = 0 ; j < 9 ; j++ )
        {
            printf("%-3d",SudokuMap[i][j]);
        }
        printf("\n");
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!