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

· · 题解

在本人看来,这道题是一个大模拟

不升绿都对不起我的付出

题意简述

给定网格,完成以下任务:

题目分析

我的做法是直接模拟,先填充,如果填充时发现有矛盾,就判定此网格非法。

1. 划掉格子

遍历每一个格子,如果这个格子中有数字且从未被遍历过,就进行筛法:

先将这个格子的所有可能性全部划掉,因为这个格子已经有数字了。

再将与其同行、同列、同宫的格子全部划掉。

特别注意:只是将关于这个格子中的数字的可能性划掉,而不是所有。

2.填充格子

遍历每一个格子,如果这一个格子还没填充且可能性只有一个,就将这只可能的数填入这个格子。

关于什么时候截止,我的做法是当所有格子都没有变动后,跳出循环。

3.判断合法

我分了三个情况:

  1. 没填充的格子没有任何能填充的数字

  2. 填充了的格子行列有重复

  3. 填充了的九宫格有数不可能出现

虽然不全,但对这个题目够用了

重要提示:

因为这道题里,他的方法有缺陷,不能把所有能填充的格子填充。

有一个测试点,这一列有八个数,就空缺了一个格子,且输入合法,我七十分的代码能处理剩下的格子,但AC代码和标准代码不行。测试点输出中这个格子也是空着的。

然后就是愉快的交代码了!

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int value;
    int checked;
    int maybe[10];
}a[10][10]; //这是地图
int b[10][10]; 
void init() //这个预处理是判断两个数在不在一个九宫格内的。这是以时间换省事,大家不要学。
{
    int ti=1;
    for(int i=1;i<=9;i+=3)
    {
        for(int j=1;j<=9;j+=3)
        {
            for(int k1=0;k1<3;k1++)
            {
                for(int k2=0;k2<3;k2++)
                {
                    b[i+k1][j+k2]=ti;

                }
            }
            ti++;
        }
    }
}
bool check() //三条判断
{
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            if(a[i][j].value>0)
                continue;
            int k=0;
            for(int x=1;x<=9;x++)
                k+=a[i][j].maybe[x];
            if(k==9)
                return 1; 
        }
    }
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            if(a[i][j].value<1)
                continue;
            for(int k=1;k<=9;k++)
            {
                if(k==j||k==i)
                    continue;
                if(a[i][j].value==a[i][k].value||a[i][j].value==a[k][j].value)
                    return 1;
            }
        }
    }
    for(int k=1;k<=9;k++)
    {
        for(int i=1;i<=9;i+=3)
        {
            for(int j=1;j<=9;j+=3)
            {
                int num=0;
                for(int k1=0;k1<3;k1++)
                    for(int k2=0;k2<3;k2++)
                        num+=a[i+k1][j+k2].maybe[k];
                if(num==9)
                {
                    bool f=0;
                    for(int k1=0;k1<3;k1++)
                        for(int k2=0;k2<3;k2++)
                            if(a[i+k1][j+k2].value==k)
                            {
                                f=1;
                                break;
                            }
                    if(!f)
                        return 1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    init();
    string s;
    for(int i=1;i<=9;i++)
    {
        cin>>s;
        for(int j=0;j<s.size();j++)
            a[i][j+1].value=s[j]-'0',a[i][j].checked=0;
    }

    bool flag=1;
    while(flag)
    {
        flag=0;
        for(int i=1;i<=9;i++) //交叉影线
        {
            for(int j=1;j<=9;j++)
            {
                if(a[i][j].value>0&&!a[i][j].checked)
                {
                    for(int k=1;k<=9;k++)
                        a[i][j].maybe[k]=1;
                    for(int k=1;k<=9;k++)
                        a[i][k].maybe[a[i][j].value]=1;
                    for(int k=1;k<=9;k++)
                        a[k][j].maybe[a[i][j].value]=1; 
                    for(int k1=1;k1<=9;k1++)
                    {
                        for(int k2=1;k2<=9;k2++)
                        {
                            if(b[k1][k2]==b[i][j])
                                a[k1][k2].maybe[a[i][j].value]=1;
                        }
                    }
                    flag=1;
                    a[i][j].checked=1;
                }
            }
        }

        for(int k=1;k<=9;k++) //填格 
        {
            for(int i=1;i<=9;i+=3)
            {
                for(int j=1;j<=9;j+=3)
                {
                    int num=0,x,y;
                    for(int k1=0;k1<3;k1++)
                    {
                        for(int k2=0;k2<3;k2++)
                        {
                            if(a[i+k1][j+k2].maybe[k]==0)
                            {
                                num++;
                                x=i+k1;
                                y=j+k2; 
                            } 
                        }
                    }
                    if(num==1)
                        a[x][y].value=k;
                }
            }
        } 
    }
    if(check())
    {
        cout<<"ERROR";
        return 0; 
    }
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            if(a[i][j].value>0)
                cout<<a[i][j].value;
            else
                cout<<'.';
        }
        cout<<endl;
    }
    return 0; //撒花!!!
}

整整一百七十行代码啊~花了我一下午

完结撒花!

等等!

还有能正确处理所有数独的七十分代码,就当做送给大家了!

数独代码

输入格式同本题

作者写了两个小时,点个赞再走吧~