4.靶形数独

(sudoku.pas/c/cpp)

【问题描述】

小城和小华都是热爱数学的好学生, 近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,

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

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

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

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

【输入】

输入文件名为 sudoku.in。

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

【输出】

输出文件 sudoku.out 共 1 行。

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

【输入输出样例 1】

sudoku.in

sudoku.out

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

2829

【输入输出样例 2】

sudoku.in

sudoku.out

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

2852

【数据范围】

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

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

【思路】

Dancing Links X

这道题用搜索做只过了80分。

很多人提到可以用DLX算法求解数独,在下还没有理解这里只贴一个别人的代码:

【搜索_80】

 #include<iostream>
#include<algorithm>
#include<vector>
#define FOR(a,b,c) for(int a=(b);a<(c);a++)
using namespace std;
const int maxn = +;
const int N=;;
struct Node{
int x,y;
Node(const int x,const int y) {
this->x=x; this->y=y;
}
vector<int> can;
bool operator <(const Node& rhs) const{
return can.size()<rhs.can.size(); //?ù?Y?é??μ?êy×??àéù′óD?μ?′ó??Dò
}
};
vector<Node> nodes;
int R[maxn][maxn],C[maxn][maxn],S[maxn][maxn];
int vis[maxn][maxn];
int ans=-; inline int ID(int i,int j) { return (i/)*+(j/); }
inline int score(int i,int j,int k) {
if(i== && j==) return *k;
if(i>= && i<= && j>= && j<=) return *k;
if(i>= && i<= && j>= && j<=) return *k;
if(i>= && i<= && j>= && j<=) return *k;
return *k;
}
inline int jisuan(int x,int y) {
if(vis[x][y]) return (<<);
int res=;
for(int i=;i<N;i++) {
//if(vis[x][i]) res++;
//if(vis[i][y]) res++;
}
for(int i=;i<N;i++) if(S[ID(x,y)][i]) res++;
return res;
}
int nc;
void dfs(int d,int sum) {
if(d==nc){
ans=max(ans,sum);
return ; //
}
int _max=(<<),_maxi;
for(int i=;i<nc;i++) {
int tmp=jisuan(nodes[i].x,nodes[i].y);
if(tmp<_max) {
_max=tmp;
_maxi=i;
}
}
int x=nodes[_maxi].x , y=nodes[_maxi].y;
FOR(j,,nodes[_maxi].can.size()) {
int i=nodes[_maxi].can[j];
if((R[x][i])||(C[y][i])||(S[ID(x,y)][i])) continue;
R[x][i]=C[y][i]=S[ID(x,y)][i]=; vis[x][y]=;
dfs(d+,sum+score(x,y,i));
R[x][i]=C[y][i]=S[ID(x,y)][i]=; vis[x][y]=;
}
}
int main() {
ios::sync_with_stdio(false);
int x;
int sum=;
FOR(i,,N) FOR(j,,N) {
cin>>x;
if(x==) nodes.push_back(Node(i,j)); //???????′ì?μ?μ?
else {
vis[i][j]=;
R[i][x]=C[j][x]=S[ID(i,j)][x]=;
sum+= score(i,j,x); //±eíüá?í3???-à′μ?·?êy
}
}
for(int i=;i<nodes.size();i++){
int x=nodes[i].x,y=nodes[i].y;
for(int j=;j<=;j++) if((!R[x][j])&&(!C[y][j])&&(!S[ID(x,y)][j])) nodes[i].can.push_back(j);
}
nc=nodes.size();
dfs(,sum);
cout<<ans;
return ;
}

【DLX_AC】

 #include <stdio.h>
#include <stdlib.h>
#define con(i) (1 << (i))
#define getid(i, j) ((i) / 3 * 3 + (j) / 3)
#define getidorder(i, j) (3 * ((i) - (i) / 3 * 3) + (j) - (j) / 3 * 3)
int map[][];
int row[];
int n_row[], n_line[];
int small[];
int f[]; int ans;
int sore[][] = { {, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , } }; void getgrade(void)
{
int i, j;
int t = ;
for(i = ; i < ; i++){
for(j = ; j < ; j++){
t += map[i][j] * sore[i][j];
}
}
if(ans < t){
ans = t;
}
} int so[], count[];
int end; void srch(int now)
{
int i, j, p;
int pos, k;
if(now == ){
getgrade();
return;
}
i = so[now];
if(count[i] == ){
srch(now + );
return;
}
count[i]--;
p = ^ row[i];
p = p & -p;
row[i] |= p;
j = f[p]; pos = ^ (n_row[i] | n_line[j] | small[getid(i, j)]);
while(pos > ){
k = pos & -pos;
pos ^= k;
n_row[i] |= k;
n_line[j] |= k;
small[getid(i, j)] |= k;
map[i][j] = f[k] + ;
srch(now);
n_row[i] ^= k;
n_line[j] ^= k;
small[getid(i, j)] ^= k;
} count[i]++;
row[i] ^= p;
} int main(int argc, char **argv)
{
int i, j, t;
for(i = , j = ; i <= ; i <<= , j++){
f[i] = j;
}
for(i = ; i < ; i++){
for(j = ; j < ; j++){
scanf("%d", &map[i][j]);
if(map[i][j] != ){
row[i] |= con(j);
t = con(map[i][j] - );
if(((n_row[i] & t) != ) || ((n_line[j] & t) != ) || ((small[getid(i, j)] & t) != )){
printf("-1\n");
return ;
}
n_row[i] |= t;
n_line[j] |= t;
small[getid(i, j)] |= t;
}else{
count[i]++;
}
}
}
for(i = ; i < ; i++){
so[i] = i;
}
for(i = ; i < ; i++){
for(j = i + ; j < ; j++){
if(count[so[i]] > count[so[j]]){
so[i] ^= so[j];
so[j] ^= so[i];
so[i] ^= so[j];
}
}
}
for(i = ; count[so[i]] == ; i++){ ; }
srch(i);
if(ans == ){
printf("-1\n");
return ;
}
printf("%d\n", ans);
return ;
}

NOIP2009 靶形数独的更多相关文章

  1. NOIP2009靶形数独[DFS 优化]

    描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教,Z 博士拿出了他最近发明的“靶形数独 ...

  2. [NOIP2009]靶形数独 题解

    407. [NOIP2009] 靶形数独 时间限制:5 s   内存限制:128 MB [问题描述] 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低. ...

  3. [NOIP2009] 靶形数独(搜索+剪枝)

    题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...

  4. NOIP2009靶形数独

    题目描述: 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“ ...

  5. [NOIP2009] 靶形数独(搜索)

    P1074 靶形数独 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士 ...

  6. NOIP2009靶形数独(暴搜)

    题目传送门 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z博士请教,Z博士拿出了他最近发明 ...

  7. Vijos1775 CodeVS1174 NOIP2009 靶形数独

    靶形数独 描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教, Z 博士拿出了他最近发 ...

  8. [NOIP2009] 靶形数独 骚气的大爆搜

    这两天OD留的题是搜索,这个东西,就是历年的NOIP压轴题嘛.做了几道什么斗地主啊啥的,感觉还是这题我还懂点. 这道题的搜(xia)索(da)思路是这样的:预处理出一切能处理的东西. 数独大家都了解吧 ...

  9. [NOIP2009]靶形数独 深搜+枝杈优化

    这道题,又是一位玄学搜索...... 我是用的蜗牛序搜的(顾名思义,@,这么搜),我正着搜80然后一反转比原来快了几十倍........一下AC....... 我的思路是这样的话我们可以从内到外或者从 ...

随机推荐

  1. SSL与TLS的区别以及介绍

    转载 :http://kb.cnblogs.com/page/197396/ SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议 ...

  2. 10个CSS简写/优化技巧

    CSS简写就是指将多行的CSS属性简写成一行,又称为CSS代码优化或CSS缩写.CSS 简写的最大好处就是能够显著减少CSS文件的大小,优化网站整体性能,更加容易阅 读. 下面介绍常见的CSS简写规则 ...

  3. android中的category静态值(转)

    提供将要执行的action的额外信息,一般在隐式地启动activity时需要用到.常见的category如下 CATEGORY_ALTERNATIVE 设置这个activity是否可以被认为是用户正在 ...

  4. CSS文件和Javascript文件的压缩

    像JQuery一样来压缩我们的CSS和JS 我们都知道一般JQuery新版本发布的时候往往会有几个不同类型文件,比如原始版本文件.最小文件以及其他配合IDE智能提示的各种版本文件,前期我们使用JQue ...

  5. 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  6. POJ 3761 Bubble Sort(乘方取模)

    点我看题目 题意 : 冒泡排序的原理众所周知,需要扫描很多遍.而现在是求1到n的各种排列中,需要扫描k遍就变为有序的数列的个数,结果模20100713,当然了,只要数列有序就扫描结束,不需要像真正的冒 ...

  7. 2013 Multi-University Training Contest 4 Who's Aunt Zhang

    看题就知道要用polya,但是当时没做出来,还是不是很熟悉polya!!! 总共有24种置换: 1. 不做任何旋转 K ^ (54 + 12 + 8) 2. 绕相对面中心的轴转 1) 90度 K ^ ...

  8. BCB6编译LUA5.15成功!

    由于想要在一个原生应用里提供脚本功能,而Python的发布不能不说是一件麻烦事.因为所需要的脚本功能很简单,所以决定试试传说中的Lua. 第一步,下载源码.虽然Lua有提供二进制版本下载,但是因为我是 ...

  9. Android:@id和@+id

    @id代表引用已有的id,而@+id是新增加一个id 如果使用@+id/name形式,当R.java中存在名为name变量时,则该组件会使用该变量的值作为标识.如果不存在该变量,则添加一个新的变量,并 ...

  10. MVC 的HTTP请求

    MVC 的HTTP请求过程(以IIS为例) 通过Browser发过请求给IIS(get/post) IIS得到请求后,再把请求转给aspnet_iisapi.dll处理,通过asp.net的一些框架的 ...