NOIP2009 靶形数独
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 靶形数独的更多相关文章
- NOIP2009靶形数独[DFS 优化]
描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教,Z 博士拿出了他最近发明的“靶形数独 ...
- [NOIP2009]靶形数独 题解
407. [NOIP2009] 靶形数独 时间限制:5 s 内存限制:128 MB [问题描述] 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低. ...
- [NOIP2009] 靶形数独(搜索+剪枝)
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...
- NOIP2009靶形数独
题目描述: 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“ ...
- [NOIP2009] 靶形数独(搜索)
P1074 靶形数独 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士 ...
- NOIP2009靶形数独(暴搜)
题目传送门 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z博士请教,Z博士拿出了他最近发明 ...
- Vijos1775 CodeVS1174 NOIP2009 靶形数独
靶形数独 描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教, Z 博士拿出了他最近发 ...
- [NOIP2009] 靶形数独 骚气的大爆搜
这两天OD留的题是搜索,这个东西,就是历年的NOIP压轴题嘛.做了几道什么斗地主啊啥的,感觉还是这题我还懂点. 这道题的搜(xia)索(da)思路是这样的:预处理出一切能处理的东西. 数独大家都了解吧 ...
- [NOIP2009]靶形数独 深搜+枝杈优化
这道题,又是一位玄学搜索...... 我是用的蜗牛序搜的(顾名思义,@,这么搜),我正着搜80然后一反转比原来快了几十倍........一下AC....... 我的思路是这样的话我们可以从内到外或者从 ...
随机推荐
- 1200: [HNOI2005]木梳 - BZOJ
Description Input 第一行为整数L,其中4<=L<=100000,且有50%的数据满足L<=104,表示木板下侧直线段的长.第二行为L个正整数A1,A2,…,AL ...
- redis 在windows 上的安装与使用
1.redis-windows 最近在做一个抢拍模块,由于过于平凡的insert与update I/O受不了,故只好把东西放内存里,等拍卖结束了,在写入磁盘. 至于为什么要用window呢? 因为服务 ...
- HTTP协议的几个重要概念
转自:http://ice-cream.iteye.com/blog/77549 1.连接(Connection):一个传输层的实际环流,它是建立在两个相互通讯的应用程序之间. 2.消息(Messag ...
- 团体程序设计天梯赛-练习集L1-008. 求整数段和
L1-008. 求整数段和 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 杨起帆 给定两个整数A和B,输出从A到B的所有整数以及这些 ...
- [笨木头FireFly01]入门篇1·最简单的服务端和客户端连接
原地址:http://www.9miao.com/question-15-53938.html 最近一直在写游戏,几乎没有来写教程了,打算放慢一下脚步,学学新东西.那为嘛我要学FireFly呢? 之前 ...
- POJ2526+简单几何
题意:给定的这些点是否有一个对称中心. PS:我写得有点啰嗦.. 就是把小的x和大的x进行匹配. #include<stdio.h> #include<algorithm> # ...
- codeforces #313 div1 C
同BZOJ 3782 上学路线 QAQ 还比那个简单一点 把坐标(1,1)-(n,m)平移成(0,0)-(n-1,m-1) 设dp[i]表示从(1,1)出发第一次经过障碍且到达第i个障碍的方案数 首先 ...
- cctype头文件(字符处理库)的使用
C++ 中cctype头文件的使用 头文件cctype(字符处理库)中定义了有关字符判断与处理的库函数,使用前要包含头文件: #include <cctype> using namespa ...
- linux page cache和buffer cache
主要区别是,buffer cache缓存元信息,page cache缓存文件数据 buffer 与 cache 是作为磁盘文件缓存(磁盘高速缓存disk cache)来使用,主要目的提高文件系统系性能 ...
- 隐马尔科夫模型 介绍 HMM python代码
#HMM Forward algorithm #input Matrix A,B vector pi import numpy as np A=np.array([[0.5,0.2,0.3],[0.3 ...