codevs 数独系列 题解报告

24 篇文章 0 订阅
10 篇文章 0 订阅

4966 简单数独 4491 验证数独 2207 验证数独
2924 数独挑战 1174 靶形数独

一共5道题目,全都和数独有关:

4966 简单数独
时间限制: 1 s
空间限制: 1000 KB
题目等级 : 黄金 Gold
题解
题目描述 Description
某一天,小强忽然迷上了数独,他想从最简单的数独做起,即4*4的数独,然而他仍然做不出来,所以想请你帮帮他。4*4即每个数字在每一行、每一列和每一区只能出现一次。

输入描述 Input Description
4行4列。

每个数字用空格隔开。

0代表要填的数.

输出描述 Output Description
输出答案。

排成4行4列。

每个数字用空格隔开.

样例输入 Sample Input
0 0 4 0

2 0 0 0

1 0 0 0

0 0 3 0

样例输出 Sample Output
3 1 4 2

2 4 1 3

1 3 2 4

4 2 3 1

数据范围及提示 Data Size & Hint
保证有且只有一个解

首先T1;
简单数独,
一个4*4的
简单的DFS枚举即可
h[][]为行的判重,l为列
s为小区间

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==4? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=4,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
    if(h[x][k])return 0;
    if(l[y][k])return 0;
    int ll=(x-1)/2*2+(y-1)/2+1;
    if(g[ll][k])return 0;
    h[x][k]=1;
    l[y][k]=1;
    g[ll][k]=1;
    b[x][y]=k;
    return 1;
}
void del(int x,int y,int k)
{
    h[x][k]=0;
    l[y][k]=0;
    g[(x-1)/2*2+(y-1)/2+1][k]=0;
    b[x][y]=0;
}
bool vv=0;
void dfs(int x,int y)
{
    if(vv)return;
    //if(clock()>1000)return;
    if(x==5&&y==1)
    {
        for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<b[i][j]<< " ";
        }cout<<endl;
    }
        vv=1;
        return;
    }
    if(b[x][y])
    {
        searchnext(x,y);
    }else
    {
        for(int i=1;i<=4;i++)
        {
            if(add(x,y,i))
            {
                searchnext(x,y);
                del(x,y,i);
            }

        }
    }
}
int main()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            if(a[i][j])
            {
                add(i,j,a[i][j]);
            }
        }
    }
    dfs(1,1);

}

然后T2
4491 验证数独
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 青铜 Bronze
题解
题目描述 Description
具体规则如下:

每一行都用到1、2、3、4、5、6、7、8、9,位置不限;

每一列都用到1、2、3、4、5、6、7、8、9,位置不限;

每3×3的格子(共九个这样的格子)都用到1、2、3、4、5、6、7、8、9,位置不限。

游戏的过程就是用1、2、3、4、5、6、7、8、9填充空白,并要求满足每行、每列、每个九宫格都用到1、2、3、4、5、6、7、8、9。

如下是一个正确的数独:

5 8 1 4 9 3 7 6 2

9 6 3 7 1 2 5 8 4

2 7 4 8 6 5 9 3 1

1 2 9 5 4 6 3 7 8

4 3 6 1 8 7 2 9 5

7 5 8 3 2 9 1 4 6

8 9 2 6 7 1 4 5 3

6 1 5 9 3 4 8 2 7

3 4 7 2 5 8 6 1 9

输入描述 Input Description
输入n个数独,你来验证它是否违反规则。

第一行为数独个数,第二行开始为第一个数独,之后为第二个,至第n个。

注意!每个数独之间有一个回车隔开!

输出描述 Output Description
若正确则输出”Right”若不正确则输出”Wrong”,输出一个换一行。

样例输入 Sample Input
2

5 8 1 4 9 3 7 6 2

9 6 3 7 1 2 5 8 4

2 7 4 8 6 5 9 3 1

1 2 9 5 4 6 3 7 8

4 3 6 1 8 7 2 9 5

7 5 8 3 2 9 1 4 6

8 9 2 6 7 1 4 5 3

6 1 5 9 3 4 8 2 7

3 4 7 2 5 8 6 1 9

1 2 3 4 5 6 7 8 9

2 3 4 5 6 7 8 9 1

3 4 5 6 7 8 9 1 2

4 5 6 7 8 9 1 2 3

5 6 7 8 9 1 2 3 4

6 7 8 9 1 2 3 4 5

7 8 9 1 2 3 4 5 6

8 9 1 2 3 4 5 6 7

9 1 2 3 4 5 6 7 8

样例输出 Sample Output
Right

Wrong

数据范围及提示 Data Size & Hint
1≤n≤20(输入的数独个数)。

不论输入的数独是错误的还是正确的,数据都保证每个数在1-9之间,即只会出现因为有相同的数而导致违反规则,而不会因为数字超出了1-9的范围而违反规则。

这个题不让解数独,只要判断是否正确,也就是同一行同一列,同意区间,有没有相同 的就好,
和上一题一样,设3个判重数组,一一枚举即可;;

代码::

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
    if(h[x][k])return 0;
    if(l[y][k])return 0;
    int ll=(x-1)/3*3+(y-1)/3+1;
    if(g[ll][k])return 0;
    h[x][k]=1;
    l[y][k]=1;
    g[ll][k]=1;
    b[x][y]=k;
    return 1;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        memset(h,0,sizeof(h));
        memset(l,0,sizeof(l));
        memset(g,0,sizeof(g));
        bool vv=0;
        for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            if(a[i][j])
            {
                if(!add(i,j,a[i][j]))
                {
                    vv=1;
                }
            }
        }
    }
    if(!vv)
        cout<<"Right\n";
        else
        cout<<"Wrong\n";
    }
}

T3‘
2924 数独挑战
时间限制: 1 s
空间限制: 1000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
“芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏。”这是英国《每日邮报》2012年6月30日的一篇报道。这个号称“世界最难数独”的“超级游戏”,却被扬州一位69岁的农民花三天时间解了出来。

看到这个新闻后,我激动不已,证明我们OI的实力的机会来了,我们虽然不是思考能力最快、头脑最聪明的人,但是我们可以保证在1s之内解题。

好了废话不多说了……

数独是一种填数字游戏,英文名叫Sudoku,起源于瑞士,上世纪70年代由美国一家数学逻辑游戏杂志首先发表,名为Number Place,后在日本流行,1984年将Sudoku命名为数独,即“独立的数字”的省略,解释为每个方格都填上一个个位数。2004年,曾任中国香港高等法院法官的高乐德(Wayne Gould)把这款游戏带到英国,成为英国流行的数学智力拼图游戏。

  玩家需要根据9×9盘面上的已知数字,推理出所有剩余位置(数据表示为数字0)的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。

现在给你一个数独,请你解答出来。每个数独保证有解且只有一个。

输入描述 Input Description
9行9列。

每个数字用空格隔开。0代表要填的数

行末没有空格,末尾没有回车。

输出描述 Output Description
输出答案。

排成9行9列。

行末没有空格,结尾可以有回车。

样例输入 Sample Input
2 0 0 0 1 0 8 9 0
0 0 7 0 0 0 0 0 0
0 0 0 9 0 0 0 0 7
0 6 0 0 0 1 3 0 0
0 9 0 7 3 4 0 8 0
0 0 3 6 0 0 0 5 0
6 0 0 0 0 2 0 0 0
0 0 0 0 0 0 1 0 0
0 5 9 0 8 0 0 0 3

样例输出 Sample Output
2 4 5 3 1 7 8 9 6
9 1 7 2 6 8 5 3 4
3 8 6 9 4 5 2 1 7
4 6 2 8 5 1 3 7 9
5 9 1 7 3 4 6 8 2
8 7 3 6 2 9 4 5 1
6 3 8 1 7 2 9 4 5
7 2 4 5 9 3 1 6 8
1 5 9 4 8 6 7 2 3

数据范围及提示 Data Size & Hint
保证有解,每个数独都由http://oubk.com数独网提供。

其中数据hard1.in为芬兰数学家提供。

这个题就是T1的升级版
求一个9*9的数独
其实程序一样,只是某些数变了而已;;

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
    if(h[x][k])return 0;
    if(l[y][k])return 0;
    int ll=(x-1)/3*3+(y-1)/3+1;
    if(g[ll][k])return 0;
    h[x][k]=1;
    l[y][k]=1;
    g[ll][k]=1;
    b[x][y]=k;
    return 1;
}
void del(int x,int y,int k)
{
    h[x][k]=0;
    l[y][k]=0;
    g[(x-1)/3*3+(y-1)/3+1][k]=0;
    b[x][y]=0;
}
bool vv=0;
void dfs(int x,int y)
{
    if(vv)return;
    //if(clock()>1000)return;
    if(x==10&&y==1)
    {
        for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<b[i][j]<< " ";
        }cout<<endl;
    }
        vv=1;
        return;
    }
    if(b[x][y])
    {
        searchnext(x,y);
    }else
    {
        for(int i=1;i<=9;i++)
        {
            if(add(x,y,i))
            {
                searchnext(x,y);
                del(x,y,i);
            }

        }
    }
}
int main()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            if(a[i][j])
            {
                add(i,j,a[i][j]);
            }
        }
    }
    dfs(1,1);

}

T4
1174 靶形数独 2009年NOIP全国联赛提高组
时间限制: 4 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,
Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有9 个3 格宽×3 格
高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些

数字,利用逻辑推理,在其他的空格上填入1 到9 的数字。每个数字在每个小九宫格内不能
重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。

上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为9 分,再外面一圈(蓝色区域)每个格子为8 分,蓝色区域外面一圈(棕
色区域)每个格子为7 分,最外面一圈(白色区域)每个格子为6 分,如上图所示。比赛的
要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为2829。游
戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。

输入描述 Input Description
一共 9 行。每行9 个整数(每个数都在0—9 的范围内),表示一个尚未填满的数独方
格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。

输出描述 Output Description
输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。

样例输入 Sample Input
【输入输出样例 1】

7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2

【输入输出样例 2】

0 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6

样例输出 Sample Output
【输入输出样例 1】

2829

【输入输出样例 1】

2852

数据范围及提示 Data Size & Hint
【数据范围】
40%的数据,数独中非0 数的个数不少于30。
80%的数据,数独中非0 数的个数不少于26。
100%的数据,数独中非0 数的个数不少于24。

这个题是T3的升级版,对于每个位置上的数给了价值,
做法就是dfs出数独的每一种情况,之后计算得分,取最大值;
但是会TLE;
codevs加上卡时之后80分。
但是,将输入倒过来就能AC了;
看来是出题人故意卡的顺序读入;

代码::

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
int getscore(int x,int y,int k)
{
    if(x==y&&x==5)
    {
        return k*10;
    }
    if(x==1||x==n||y==1||y==n)return 6*k;
    if(x==2||x==8||y==2||y==8)return 7*k;
    if(x==3||x==7||y==3||y==7)return 8*k;
    if(x==4||x==6||y==4||y==6)return 9*k;
}
bool add(int x,int y ,int k)
{
    if(h[x][k])return 0;
    if(l[y][k])return 0;
    int ll=(x-1)/3*3+(y-1)/3+1;
    if(g[ll][k])return 0;
    h[x][k]=1;
    l[y][k]=1;
    g[ll][k]=1;
    b[x][y]=k;
    score+=getscore(x,y,k);
    return 1;
}
void del(int x,int y,int k)
{
    h[x][k]=0;
    l[y][k]=0;
    g[(x-1)/3*3+(y-1)/3+1][k]=0;
    b[x][y]=0;
}
void dfs(int x,int y)
{
    //if(clock()>1000)return;
    if(x==10&&y==1)
    {
        ans=max(ans,score);
        return;
    }
    if(b[x][y])
    {
        searchnext(x,y);
    }else
    {
        for(int i=1;i<=9;i++)
        {
            int t=score;
            if(add(x,y,i))
            {
                searchnext(x,y);
                del(x,y,i);
                score=t;
            }

        }
    }
}
int main()
{
    for(int i=n;i>=1;i--)
    {
        for(int j=n;j>=1;j--)
        {
            cin>>a[i][j];
            if(a[i][j])
            {
                add(i,j,a[i][j]);
            }
        }
    }
    dfs(1,1);
    cout<<ans;
}

呜啦啦啦啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值