题解 P6410 【[COCI2008-2009#3] CROSS】

· · 题解

这题看起来很麻烦,可是写起来好像比较简单(吗?)。

官方代码中变量命名不是英文,看不懂在写什么。。。

还是自己写了一下。

I. 题意

首先判定数独是否合法。

合法便需要反复使用交叉影线法,推导出格子的值。

II. 实现合法性判断

模拟。

首先判断行、列、宫是否有重复的。

(1) 用三个二维数组分别记录某个数字某项目(每行、每列、每宫)有没有出现过。

(2) 遇到数字,把对应三个项目作注记。若在此前已有注记,说明这数独不合法。

然后判断是否每一个宫都能填入数字1-9

如果发现某数字在某宫中只有一个位置能填入,那么马上填入。

如果只有这里没写对,会得到奇妙的97 pts。

流程是这样的...

那么对于每个数字进行检查,如果一个宫没有合法位置再填入这个数字(当然,这个宫本身没有这个数字的话),那就是不合法的。

如果只有一种可能的位置,那么就马上填入。

这部分时间复杂度是9\times9\times9,也就是O(1)的。

III. 实现交叉影线法

如果像我那么懵懂的话,可能不知道要运用多少次才行,那么订一个大点的数,例如500,便十分的足够了。

每一次交叉影线法,我们对于每一个数字...

  1. 先开一个新的数组,用于剔除不合法位置。

  2. 剔除不合法位置,在新开的二维数组把这些位置标上状态不合法。

  3. 最后查看每一个宫,如果合法位置唯一,那么填入。

感觉讲得不太好,可以看看代码。

此部分时间复杂度是500\times9\times9\times9\times9\times9,也是O(1)的。

IV. 代码

#include <iostream>
#include <cstdio>
using namespace std;
int line[11][11],column[11][11],gg[11][11];
char str[21];
int mat[11][11];
int get_gg(int i,int j)
{
    int x=(i-1)/3+1;
    int y=(j-1)/3+1;
    return (x-1)*3+y;
}
int mat2[11][11];
int begingg[11],endgg[11];
int main()
{
    int flag=0;
    for (int i=1;i<=9;i++)
    {
        scanf("%s",str+1);
        for (int j=1;j<=9;j++)
        {
            if (str[j]!='.')
            {
                mat[i][j]=str[j]-48;
                if (line[i][mat[i][j]]) flag=1;
                else line[i][mat[i][j]]=1;
                if (column[j][mat[i][j]]) flag=2;
                else column[j][mat[i][j]]=1;
                if (gg[get_gg(i,j)][mat[i][j]]) flag=3;
                else gg[get_gg(i,j)][mat[i][j]]=1;
            }
        }
    }
    if (flag)
    {
        printf("ERROR");
        return 0;
    }
    begingg[1]=1;begingg[2]=4;begingg[3]=7;
    endgg[1]=3;endgg[2]=6;endgg[3]=9;
    for (int i=1;i<=9;i++) //check every number
    {
        for (int indggx=1;indggx<=3;indggx++) //check every 3*3 block
        {
            for (int indggy=1;indggy<=3;indggy++)
            {
                if (gg[(indggx-1)*3+indggy][i]==1) continue;
                int tmpflag=0;
                for (int indline=begingg[indggx];indline<=endgg[indggx];indline++) //we want each 3*3 block has this number, or keep a possible position for this number
                {
                    for (int indcolumn=begingg[indggy];indcolumn<=endgg[indggy];indcolumn++)
                    {
                        if (line[indline][i]||column[indcolumn][i]||gg[get_gg(indline,indcolumn)][i]||mat[indline][indcolumn]) continue;
                        tmpflag++; //if this place is possible, it shows that this block is likely to be following the rules
                    }
                }
                if (!tmpflag) {flag=true;}
                if (tmpflag==1)
                {
                    for (int indline=begingg[indggx];indline<=endgg[indggx];indline++) //we want each 3*3 block has this number, or keep a possible position for this number
                    {
                        for (int indcolumn=begingg[indggy];indcolumn<=endgg[indggy];indcolumn++)
                        {
                            if (line[indline][i]||column[indcolumn][i]||gg[get_gg(indline,indcolumn)][i]||mat[indline][indcolumn]) continue;
                            line[indline][i]=1;
                            column[indcolumn][i]=1;
                            gg[get_gg(indline,indcolumn)][i]=1;
                            mat[indline][indcolumn]=i;
                        }
                    }
                }
            }

        }
    }
    if (flag)
    {
        printf("ERROR");
        return 0;
    }
    for (int tt=1;tt<=500;tt++) //number of using this method -- 500
    {
        for (int en=1;en<=9;en++) //for each number
        {
            for (int i=1;i<=9;i++) //clear data
            {
                for (int j=1;j<=9;j++) mat2[i][j]=0;
            }
            for (int inx=1;inx<=9;inx++) //cancel impossible unit
            {
                for (int iny=1;iny<=9;iny++)
                {
                    if (mat[inx][iny]==en)
                    {
                        for (int i=1;i<=9;i++) //mark down impossible unit
                        {
                            mat2[inx][i]=1;
                            mat2[i][iny]=1;
                        }
                        for (int i=begingg[(inx-1)/3+1];i<=endgg[(inx-1)/3+1];i++)
                        {
                            for (int j=begingg[(iny-1)/3+1];j<=endgg[(iny-1)/3+1];j++)
                            {
                                mat2[i][j]=1;
                            }
                        }
                    }
                    if (mat[inx][iny])
                    {
                        mat2[inx][iny]=1;
                    }
                }
            }
            for (int i=1;i<=3;i++) //we check through every 3*3 block to find out which place can be filled in
            {
                for (int j=1;j<=3;j++)
                {

                    if (gg[(i-1)*3+j][en]) continue;
                    for (int indline=begingg[i];indline<=endgg[i];indline++)
                    {
                        for (int indcolumn=begingg[j];indcolumn<=endgg[j];indcolumn++)
                        {

                            if (mat2[indline][indcolumn]==0)
                            {
                                flag++;
                            }
                        }
                    }
                    if (flag==1)
                    {
                        for (int indline=begingg[i];indline<=endgg[i];indline++)
                        {
                            for (int indcolumn=begingg[j];indcolumn<=endgg[j];indcolumn++)
                            {
                                if (mat2[indline][indcolumn]==0)
                                {
                                    mat[indline][indcolumn]=en;gg[get_gg(indline,indcolumn)][en]=1;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    for (int i=1;i<=9;i++)
    {
        for (int j=1;j<=9;j++)
        {
            if (mat[i][j])
            {
                printf("%d",mat[i][j]);
            }
            else printf(".");
        }
        printf("\n");
    }
}