noip2009 靶形数独

P1074 靶形数独

    • 318通过
    • 1.5K提交
  • 题目提供者洛谷OnlineJudge
  • 标签搜索/枚举2009NOIp提高组
  • 难度提高+/省选-

提交该题 讨论 题解 记录

 

题目描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他

们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,

Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格

高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 1 到 9 的数字。每个数字在每个小九宫格内不能

重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即

每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)

上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红

色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8 分,蓝色区域外面一圈(棕

色区域)每个格子为 7 分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。比赛的

要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取

更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字

的乘积的总和

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字

的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。

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

够得到的最高分数。

输入输出格式

输入格式:

 

一共 9 行。每行 9 个整数(每个数都在 0―9 的范围内),表示一个尚未填满的数独方

格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。

 

输出格式:

 

输出文件 sudoku.out 共 1 行。

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

 

输入输出样例

输入样例#1:
sudoku1
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

sudoku2
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
输出样例#1:
sudoku1
2829

sudoku2
2852

说明

【数据范围】

40%的数据,数独中非 0 数的个数不少于 30。

80%的数据,数独中非 0 数的个数不少于 26。

100%的数据,数独中非 0 数的个数不少于 24。

NOIP 2009 提高组 第四题

分析:对于这道题,首先想到的就是搜索,但是数据太大,绝对TLE,这个时候就要用一些特殊的技巧.如果我们自己来做数独题,会怎么做呢?一定会先填可选数字最少的那一格吧。搜索的顺序也是这样,每次都搜能填个数最少的那一格,就可以过了.这里有个小技巧就是怎么表示每个九宫格,具体看代码.

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
int a[10][10],fenshu[10][10],vis1[30][10],vis2[10][10],vis3[10][10],b[10][10],ans = -1;

void dfs()
{
    int x,y,step = 10;
    for (int i = 1; i <= 9; i++)
    for (int j = 1; j <= 9; j++)
    {
        if (!a[i][j])
        {
            int s = 0;
            for (int k = 1; k <= 9; k++)    
            if (!vis1[b[i][j]][k] && !vis2[i][k] && !vis3[j][k])
            s++;
            if (s < step)
            {
                step = s;
                x = i;
                y = j;
            }
        }
    }
    if (step == 10) 
    {
        int k = 0;
        for (int i = 1; i <= 9; i++)
        for (int j = 1; j <= 9; j++)
        k += a[i][j] * fenshu[i][j];
        ans = max(ans,k); 
    }
    for (int k = 1; k <= 9; k++)
    if (!vis1[b[x][y]][k] && !vis2[x][k] && !vis3[y][k])
    {
        vis1[b[x][y]][k] = vis2[x][k] = vis3[y][k] = 1;
        a[x][y] = k;
        dfs();
        a[x][y] = 0;
        vis1[b[x][y]][k] = vis2[x][k] = vis3[y][k] = 0;
    }
}

int main()
{
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    memset(vis3,0,sizeof(vis3));
    for (int i = 1; i <= 9; i++)
    for (int j = 1; j <= 9; j++)
    {
    scanf ("%d",&a[i][j]); 
    fenshu[i][j] = 10 - max(abs(i - 5),abs(j - 5));
    b[i][j] =  (i - 1) / 3 * 3 + (j - 1) / 3 + 1;
    vis1[b[i][j]][a[i][j]] = 1;
    vis2[i][a[i][j]] = 1;
    vis3[j][a[i][j]] = 1; 
}
dfs();
    printf("%d",ans);
    
    return 0;
}

codevs数据良心,洛谷坑爹!

posted @ 2016-07-28 16:54  zbtrs  阅读(2418)  评论(0编辑  收藏  举报