Evanyou Blog 彩带

  题目传送门

题目描述

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

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

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

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

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

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

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

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

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

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

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

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

的乘积的总和

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

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

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

够得到的最高分数。

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

输出共 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: 复制
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

说明

【数据范围】

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

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

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

NOIP 2009 提高组 第四题


  分析:首先膜一下five20巨佬Orz%%%。数独问题,那么就搜索呗。但是直接暴搜肯定会炸掉,那么就要考虑如何剪枝。首先很显然每一行每一列还有每一个九宫格里1-9的数字不能重复出现,那么就放三个bool数组来判断,然后还可以放一个bool数组来判断某一个位置是否放了数。但是这些肯定还不够。搜索的时候这样定义

  dfs(int rest,int sum) 

  其中rest表示当前还有多少个格子未填数字,sum表示当前得分总和。那么每次先用一个三重循环来找当前状态下,哪一个格子中可填的数最少,那就从这个格子开始填,这样可以尽可能的减少搜索的分支。具体如何实现在代码中解释。(哦,对了,这题在洛谷上是开了O2才过的,应该还有更优的优化,但是这里蒟蒻也想不到什么更好的优化了,欢迎各位大佬来踩,指导一下蒟蒻)

  Code:

// luogu-judger-enable-o2
//It is made by HolseLee on 21rd Apr 2018
//Luogu.org P1074
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=10;
int ans=-1,a[N][N];
bool vis[N][N],vh[N][N],vl[N][N],vm[N][N];
int w[N][N]={
  {0,0,0,0,0,0,0,0,0,0},
  {0,6,6,6,6,6,6,6,6,6},
  {0,6,7,7,7,7,7,7,7,6},
  {0,6,7,8,8,8,8,8,7,6},
  {0,6,7,8,9,9,9,8,7,6},
  {0,6,7,8,9,10,9,8,7,6},
  {0,6,7,8,9,9,9,8,7,6},
  {0,6,7,8,8,8,8,8,7,6},
  {0,6,7,7,7,7,7,7,7,6},
  {0,6,6,6,6,6,6,6,6,6}};
inline int read()
{
  char ch=getchar();int num=0;
  while(ch<'0'||ch>'9')
    ch=getchar();
  while(ch>='0'&&ch<='9'){
    num=num*10+ch-'0';
    ch=getchar();}
  return num;
}
inline int getm(int x,int y)
{
  if(x<=3){
    if(y<=3)return 1;
    if(y<=6)return 2;
    return 3;}
  else if(x<=6){
    if(y<=3)return 4;
    if(y<=6)return 5;
    return 6;}
  else{
    if(y<=3)return 7;
    if(y<=6)return 8;
    return 9;}
}
inline void dfs(int rest,int sum)
{
  if(rest==0){
    ans=max(ans,sum);return;}
  int maxn=1e9+7,opt,x,y;
  for(int i=1;i<=9;i++)
    for(int j=1;j<=9;j++)
      if(!vis[i][j]){
      opt=0;
      for(int k=1;k<=9;k++)
    if(!vh[i][k]&&!vl[j][k]&&!vm[getm(i,j)][k])opt++;
      if(opt<maxn)maxn=opt,x=i,y=j;}
  opt=getm(x,y);
  for(int i=1;i<=9;i++)
    if(!vh[x][i]&&!vl[y][i]&&!vm[opt][i]){
      vh[x][i]=vl[y][i]=vm[opt][i]=vis[x][y]=true;
      dfs(rest-1,sum+w[x][y]*i);
      vh[x][i]=vl[y][i]=vm[opt][i]=vis[x][y]=false;
  }
}
int main()
{
  int cnt=0,tot=0;
  for(int i=1;i<=9;i++)
    for(int j=1;j<=9;j++){
      a[i][j]=read();
      if(a[i][j]>0){
    cnt++;
    vis[i][j]=true;
    vh[i][a[i][j]]=true;
    vl[j][a[i][j]]=true;
    vm[getm(i,j)][a[i][j]]=true;
    tot+=(w[i][j]*a[i][j]);
      }}
  dfs(81-cnt,tot);
  printf("%d",ans);
  return 0;
}

 

原文地址:https://www.cnblogs.com/cytus/p/8901935.html