天天看点

wikioi-天梯-提高一等-启发式搜索-1074:靶形数独

题目描述 Description

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

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

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

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

高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些

数字,利用逻辑推理,在其他的空格上填入1 到9 的数字。每个数字在每个小九宫格内不能

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

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

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

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

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

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

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

的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为2829。游

戏规定,将以总分数的高低决出胜负。

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

够得到的最高分数。

wikioi-天梯-提高一等-启发式搜索-1074:靶形数独

输入描述 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。

类型:图论  难度:2.5

题意:给出一个数独(每行每列,每一个3*3区域都不出现重复的数字),每个格子给出一个分值,由内向外递增,整个数独的分值是每个格子的分值乘以填入格子的数,再求和。求分值最高的合法数独。

分析:整体思想还是枚举每个空白格子的可能的取值,然后用dfs搜索,但是这种盲目搜索可能会造成很大的搜索空间,所以利用启发式搜索的思想,可以看出,由于要求每行每列,每一个3*3区域都不出现重复的数字,那么如果这一行/列给出的数字越多,那么空白格子枚举的次数就越少,那么从这种格子开始搜索,搜索空间就小。

所以在进行dfs之前,先按每行/列给出的数字的个数对行/列排序,给出的数字越多,该行/列优先级越高,然后按照这个优先级计算所有空白格子的遍历顺序,按照先行后列的优先级排序,然后按照这个顺序进行dfs,找到一个合法数独后,记录最大值。

代码:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;

int m[9][9];
int s[9][9] = {
    {6,6,6,6,6,6,6,6,6},
    {6,7,7,7,7,7,7,7,6},
    {6,7,8,8,8,8,8,7,6},
    {6,7,8,9,9,9,8,7,6},
    {6,7,8,9,10,9,8,7,6},
    {6,7,8,9,9,9,8,7,6},
    {6,7,8,8,8,8,8,7,6},
    {6,7,7,7,7,7,7,7,6},
    {6,6,6,6,6,6,6,6,6},
    };
int que[90][2],qlen;

int cmp(const void*a, const void*b)
{
    if(((int*)b)[1]==((int*)a)[1])
        return ((int*)a)[0]-((int*)b)[0];
    return ((int*)b)[1]-((int*)a)[1];
}

int fun(int pos)
{
    if(pos>=qlen)
        return 0;
    
    int i = que[pos][0];
    int j = que[pos][1];
        
    bool inv[10];
    memset(inv,0,sizeof(inv));
    for(int k=0; k<9; k++)
    {
        inv[m[i][k]] = 1;
        inv[m[k][j]] = 1;
    }
    for(int x=i/3*3; x<i/3*3+3; x++)
        for(int y=j/3*3; y<j/3*3+3; y++)
            inv[m[x][y]] = 1;

    int maxn = -1;
    for(int k=1; k<=9; k++)
    {
        if(inv[k]==0)
        {
            m[i][j] = k;
                
            int tmp = fun(pos+1);
            if(tmp>=0)
                if(tmp+k*s[i][j]>maxn) 
                    maxn = tmp+k*s[i][j];
            
            m[i][j] = 0;
        }
    }
    return maxn;
}

int main()
{
    int row[9][2],col[9][2];
    for(int i=0; i<9; i++)
    {
        row[i][0] = i;
        row[i][1] = 0;
        col[i][0] = i;
        col[i][1] = 0;
    }
        
    int ans = 0;
    for(int i=0; i<9; i++)
    {
        for(int j=0; j<9; j++)
        {
            cin>>m[i][j];
            if(m[i][j]>0)
            {
                row[i][1]++;
                col[j][1]++;
                ans += m[i][j]*s[i][j];
            }
        }
    }
    
    qsort(row,9,sizeof(int)*2,cmp);
    qsort(col,9,sizeof(int)*2,cmp);
    
    qlen=0;
    for(int i=0; i<9; i++)
    {
        for(int j=0; j<9; j++)
        {
            if(m[row[i][0]][col[j][0]]==0)
            {
                que[qlen][0] = row[i][0];
                que[qlen++][1] = col[j][0];
            }
        }
    }
    int tmp = fun(0);
    if(tmp<0) ans = -1;
    else ans += tmp;
    cout<<ans<<endl;
}
           

继续阅读