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. NOI考前乱写

    还有13天NOI,把各种乱七八糟的算法都重新过一遍还是比较有必要的... //HDU 5046 Airport //DancingLink #include<iostream> #incl ...

  2. 字符串转到js对象

    var obj = (new Function("return " + str))();

  3. PAT-乙级-1025. 反转链表 (25)

    1025. 反转链表 (25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 给定一个常数K以及一个单链表L,请 ...

  4. linux xxd 命令

    http://www.cnblogs.com/openix/archive/2012/04/23/2466320.html xxd -i dht.jpg dht.h

  5. 关于Application.Lock和Lock(obj)

    http://www.cnblogs.com/yeagen/archive/2012/03/01/2375610.html 1.Application.Lock和Application.UnLock一 ...

  6. java 用JNA方法调用C++动态链接库

    JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架.非常强大.易用,功能上类似与.NET的P/Invoke.你只 ...

  7. Servlet课程0425(四) Servlet实现简单用户登录验证

    Login.java //登录界面 package com.tsinghua; import javax.servlet.http.*; import java.io.*; public class ...

  8. centos6.5下Zabbix系列之Zabbix安装搭建及汉化

    最近在研究zabbix,在整理完成之后就有了写一下总结博客的想法,在我研究zabbix的时候给我很大帮助的是it你好,博客地址http://itnihao.blog.51cto.com/他做的zabb ...

  9. [转] android自动化测试之MonkeyRunner使用实例(三)

    一.使用CMD命令打开模拟器 运行monkeyrunner之前必须先运行相应的模拟器或连上设备,不然monkeyrunner无法连接设备. 1.1  用Elipse打开Android模拟器或在CMD中 ...

  10. 八大Webkit内核浏览器

    列举出时下最流行的Webkit内核浏览器,所以我们并不会做出评测和对比.PS:本文列举的浏览器有一部分为IE+Webkit双核浏览器,如果您对其他IE内核浏览器很感兴趣<抛弃数据!用体验和感觉告 ...