搜索—靶形数独

[NOIP2009 提高组] 靶形数独

题目背景

此为远古题,不保证存在可以通过任意符合要求的输入数据的程序

题目描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 \(9\) 格宽且 \(9\) 格高的大九宫格中有 \(9\)\(3\) 格宽且 \(3\) 格高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 \(1\)\(9\) 的数字。每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)

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

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 \(2829\)。游戏规定,将以总分数的高低决出胜负。

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

输入格式

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

输出格式

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

样例 #1

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

样例输出 #1

2829

样例 #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

样例输出 #2

2852

提示

从0少的行数开始填,可以优化搜索剪枝

数据规模与约定

  • 对于 \(40\%\) 的数据,数独中非 \(0\) 数的个数不少于 \(30\)
  • 对于 \(80\%\) 的数据,数独中非 \(0\) 数的个数不少于 \(26\)
  • 对于 \(100\%\) 的数据,数独中非 \(0\) 数的个数不少于 \(24\)

分析

首先我们先要会数独,数独要求每行每列每宫的数字都不相同,黑线划分出的9个块就9个宫

代码实现

#include<iostream>
#include<algorithm>
using namespace std;
int initial[10][10];
bool row[10][10],col[10][10],box[10][10];
int score,s_score[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 search(int i,int j){
    if(i<3){
        if(j<3)
            return 0;
        else if(j<6)
                return 1;
            else
                return 2;
    }
    if(i<6){
        if(j<3)
            return 3;
        else if(j<6)
                return 4;
            else
                return 5;
    }
    if(i<9){
        if(j<3)
            return 6;
        else if(j<6)
                return 7;
            else
                return 8;        
    }
    return 0;
}
struct zero
{
    int num;
    int sum;
}cal[10];
int zero_sum = 0;
int ans = -1,s[100][4];
bool cmp(zero q,zero e){
    return q.sum < e.sum;
}
int xx[9],net=0;
void dfs(int i, int j, int sco) {
    if (i == 9) {
        if (sco > ans) ans = sco;
        return;
    }

    int next_i = i, next_j = j + 1;
    if (next_j == 9) {
        next_i++;
        next_j = 0;
    }

    if (initial[i][j] == 0) {
        for (int z = 1; z <= 9; z++) {
            if (!row[i][z] && !col[j][z] && !box[search(i, j)][z]) {
                initial[i][j] = z;
                row[i][z] = col[j][z] = box[search(i, j)][z] = 1;

                dfs(next_i, next_j, sco + z * s_score[i][j]);

                initial[i][j] = 0;
                row[i][z] = col[j][z] = box[search(i, j)][z] = 0;
            }
        }
    } else {
        dfs(next_i, next_j, sco);
    }
}

int main(){
    for(int i = 0;i < 9;i ++)
        for(int j = 0;j < 9; j ++){
            cin>>initial[i][j];
            score += initial[i][j] * s_score[i][j];
            if(initial[i][j]!=0)
                {row[i][initial[i][j]] = 
                                col[j][initial[i][j]] = 
                                box[search(i,j)][initial[i][j]] = 1;
                }
            else
               {  cal[i].num = i;
        cal[i].sum++; // Change this line
        zero_sum++;}
        }
        sort(cal,cal+9,cmp);

        for(int i =0;i < 9;i++)
        xx[i]=cal[i].num;
        dfs(0,0,score);
        cout<<ans;
    return 0;
}

超时代码

点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
int initial[10][10];
bool row[10][10],col[10][10],box[10][10];
int score,s_score[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 search(int i,int j){
    if(i<3){
        if(j<3)
            return 0;
        else if(j<6)
                return 1;
            else
                return 2;
    }
    if(i<6){
        if(j<3)
            return 3;
        else if(j<6)
                return 4;
            else
                return 5;
    }
    if(i<9){
        if(j<3)
            return 6;
        else if(j<6)
                return 7;
            else
                return 8;        
    }
    return 0;
}
struct zero
{
    int num;
    int sum;
}cal[10];
int zero_sum = 0;
int ans = -1,s[100][4];
bool cmp(zero q,zero e){
    return q.sum < e.sum;
}
int xx[9],net=0;
void dfs(int i, int j, int sco) {
    if (i == 9) {
        if (sco > ans) ans = sco;
        return;
    }

    int next_i = i, next_j = j + 1;
    if (next_j == 9) {
        next_i++;
        next_j = 0;
    }

    if (initial[i][j] == 0) {
        for (int z = 1; z <= 9; z++) {
            if (!row[i][z] && !col[j][z] && !box[search(i, j)][z]) {
                initial[i][j] = z;
                row[i][z] = col[j][z] = box[search(i, j)][z] = 1;

                dfs(next_i, next_j, sco + z * s_score[i][j]);

                initial[i][j] = 0;
                row[i][z] = col[j][z] = box[search(i, j)][z] = 0;
            }
        }
    } else {
        dfs(next_i, next_j, sco);
    }
}

int main(){
    for(int i = 0;i < 9;i ++)
        for(int j = 0;j < 9; j ++){
            cin>>initial[i][j];
            score += initial[i][j] * s_score[i][j];
            if(initial[i][j]!=0)
                {row[i][initial[i][j]] = 
                                col[j][initial[i][j]] = 
                                box[search(i,j)][initial[i][j]] = 1;
                }
            else
               {  cal[i].num = i;
        cal[i].sum++; // Change this line
        zero_sum++;}
        }
        sort(cal,cal+9,cmp);

        for(int i =0;i < 9;i++)
        xx[i]=cal[i].num;
        dfs(0,0,score);
        cout<<ans;
    return 0;
}
大错特错代码
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
int initial[10][10];
bool row[10][10],col[10][10],box[10][10];
int score,s_score[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 search(int i,int j){
    if(i<3){
        if(j<3)
            return 0;
        else if(j<6)
                return 1;
            else
                return 2;
    }
    if(i<6){
        if(j<3)
            return 3;
        else if(j<6)
                return 4;
            else
                return 5;
    }
    if(i<9){
        if(j<3)
            return 6;
        else if(j<6)
                return 7;
            else
                return 8;        
    }
    return 0;
}
struct zero
{
    int num;
    int sum;
}cal[10];
int zero_sum = 0;
int ans = -1,s[100][4];
bool cmp(zero q,zero e){
    return q.sum < e.sum;
}
int xx[9],net=0;
void dfs(int count , int sco,int x) {
    if (count == zero_sum) {
        if (sco > ans) ans = sco;
        return;
    }

 // Fix: Use cal[count].num instead of x
    for (int j = 0; j < 9; j++) {
		
        if (initial[x][j] == 0) {
            for (int z = 1; z <= 9; z++) {
            	
                if (!row[x][z] && !col[j][z] && !box[search(x, j)][z]) {
                    initial[x][j] = z;
                    row[x][z] = col[j][z] = box[search(x, j)][z] = 1;
                    
                    dfs(count + 1, sco + z * s_score[x][j],x);
                    initial[x][j] = 0;
                    row[x][z] = col[j][z] = box[search(x, j)][z] = 0;
                }
            }
        }
		if(j==8)dfs(count,sco,xx[net+1]);//这个代码有问题,话说dev的debug远没有vc好用
    }
}

int main(){
    for(int i = 0;i < 9;i ++)
        for(int j = 0;j < 9; j ++){
            cin>>initial[i][j];
            score += initial[i][j] * s_score[i][j];
            if(initial[i][j]!=0)
                {row[i][initial[i][j]] = 
                                col[j][initial[i][j]] = 
                                box[search(i,j)][initial[i][j]] = 1;
                }
            else
               {  cal[i].num = i;
        cal[i].sum++; // Change this line
        zero_sum++;}
        }
        sort(cal,cal+9,cmp);

        for(int i =0;i < 9;i++)
        xx[i]=cal[i].num;
        dfs(0,score,xx[net]);
        cout<<ans;
		system("pause");
    return 0;
}
posted @ 2023-08-22 03:08  LongDz  阅读(16)  评论(0)    收藏  举报