codevs1174 靶形数独
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,
Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有9 个3 格宽×3 格
高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些
数字,利用逻辑推理,在其他的空格上填入1 到9 的数字。每个数字在每个小九宫格内不能
重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。
上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为9 分,再外面一圈(蓝色区域)每个格子为8 分,蓝色区域外面一圈(棕
色区域)每个格子为7 分,最外面一圈(白色区域)每个格子为6 分,如上图所示。比赛的
要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为2829。游
戏规定,将以总分数的高低决出胜负。
由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。
一共 9 行。每行9 个整数(每个数都在0—9 的范围内),表示一个尚未填满的数独方
格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。
输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-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
【输入输出样例 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
【输入输出样例 1】
2829
【输入输出样例 1】
2852
【数据范围】
40%的数据,数独中非0 数的个数不少于30。
80%的数据,数独中非0 数的个数不少于26。
100%的数据,数独中非0 数的个数不少于24。
我们看每个空白的格子,看看它还可以填几个数。 如果是我们在做数独的话,我们显然会先从可以填的数少的格子开始试。 所以我们可以找出每个格子可以填几个数,然后排序,先从可以填的数少的格子开始搜。
可行性剪枝:显然,这道题的不合法解就是同一行或同一列或同一个九宫格出现了相同数字,所以我们只需要知道一个格子可以填哪些数,然后只搜索这些可以填的数就可以了
最优性剪枝: 如果当前已有得分+未来可能得到的最大的分<=当前已得到的最大总分(已经找到的合法解中的最优解),则直接退出。显然未来得分不可能超过(没有填的格子数*90)。
我们再想一下,爆搜的大部分时间都浪费在了哪? 在找这个格子能够填哪些数。 这个问题能够快速解决吗? 搜索问题中,解决这种问题有一个通用方法,就是:位运算!
既然每行每列每个九宫格一共就9个数,我们就记录一下哪些数没用过。 一共9个数,想到了啥? 2^9 压位! 若第i位的二进制为1,则表示第i个数在这一行/这一列/这个九宫格还没有出现过,还可以使用。
那我们怎么找一个格子所在的该行该列该九宫格都还未出现过的数字? 三个信息and一下就可以了。 假设得到的是x,那么,x的二进制上为1的就是我们可以在这个格子里填的数字。
怎么遍历可以填的所有数字?也就是x的所有二进制位1的位?显然不能一位一位的遍历。。。。那样就成了暴力了。。。。我们希望只遍历二进制是1的位。 For (;x!=0;x-=x&-x) { y=log[x&-x]+1;//+1是因为数字是1~9,不是0~8 ……. ……. }
注意,在给这个格子选择某个数填上,dfs进入下一层之前,我们要先修改该行该列该九宫格还能填的剩余数字。 Dfs回到上一层之后,也记得修改该行该列该九宫格还能填的剩余数字。 For (;x!=0;x-=x&-x) { y=log[x&-x]+1; 记录这个格子填y,将该格子得分加入当前总分,并将该行该列该九宫格记录的还能填的数字信息and (2^10-1-(x&-x)) dfs(………); 将该格子得分从当前总分中减去,并将该行该列该九宫格记录的还能填的数字信息or (x&-x) }
代码:
①自己写的,用了map
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define mx 111
#define maxint 10000
using namespace std;
struct Node{
int x;
int y;
int a;
};
vector<Node> node;
int a[mx][mx],line[mx],col[mx],pal[mx],block[mx][mx],ok[mx][mx],sub[mx],Log[maxint],lft,maxans,ansleft;
int s_jud[][] = {,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,};
int g_jud[][] = {,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,
,,,,,,,,,};
bool cmp(Node x,Node y){
return x.a < y.a;
}
void init(){
lft = maxans = ansleft = ;
int vd = pow(,) - ,acc;
memset(line,vd,sizeof(line));
memset(col,vd,sizeof(col));
memset(block,vd,sizeof(block));
memset(pal,vd,sizeof(pal));
memset(ok,,sizeof(ok));
for(int c = ,x = ;c < maxint;c *= ,x++) Log[c] = x;
for(int i = ;i <= ;i++) sub[i] = vd - pow(,i-);
for(int i = ; i <= ;i++){
for(int j = ;j <= ;j++){
cin>>a[i][j];
if(a[i][j]){
lft++;
line[i] = line[i] & sub[a[i][j]];
col[j] = col[j] & sub[a[i][j]];
pal[g_jud[i-][j-]] = pal[g_jud[i-][j-]] & sub[a[i][j]];
ok[i][j] = ;
ansleft += a[i][j] * s_jud[i-][j-];
}
}
}
lft = - lft;
Node temp;
for(int i = ;i <= ;i++){
for(int j = ;j <= ;j++){
block[i][j] = line[i] & col[j] & pal[g_jud[i-][j-]];
acc = ;
for(int x = block[i][j];x!=;x-=x&-x) acc++;
if(ok[i][j]) continue;
temp.y = i;
temp.x = j;
temp.a = acc;
node.push_back(temp); }
}
sort(node.begin(),node.end(),cmp);
}
void opt_init(){
for(int i = ;i <lft;i++){
cout<<"No."<<i<<" ("<<node[i].x<<","<<node[i].y<<") "<<node[i].a<<endl;
}
}
int dfs(int deep,int score){
if(deep > lft){
maxans = max(score,maxans);
return score;
} int nowx = node[deep-].x,nowy = node[deep-].y,test;
int x = line[nowy] & col[nowx] & pal[g_jud[nowy-][nowx-]],y;
for(;x!=;x-=x&-x){
y=Log[x&-x]+;
score += y * s_jud[nowy-][nowx-];
test = pow(,) - - (x&-x);
line[nowy] = line[nowy] & test;
col[nowx] = col[nowx] & test;
pal[g_jud[nowy-][nowx-]] = pal[g_jud[nowy-][nowx-]] & test;
dfs(deep+,score);
score -= y * s_jud[nowy-][nowx-];
line[nowy] = line[nowy] | (x&-x);
col[nowx] = col[nowx] | (x&-x);
pal[g_jud[nowy-][nowx-]] = pal[g_jud[nowy-][nowx-]] | (x&-x);
}
}
int main(){
init();
dfs(,);
if(maxans) cout<<maxans + ansleft<<endl;
else cout<<-<<endl;
return ;
}
②ida*
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define MAX(a,b) a>b?a:b
using namespace std; int Map[][] = {}; //这个就不用解释了吧
int Nine[][] = {}; //小九宫格里每个数的使用标记,小九宫格的编号左到右,上到下,1,2,3,4,5,6,7,8,9
int Line[][] = {}; //行上每个数的使用标记
int Row[][] = {}; //列上每个数的使用标记
int FQueL[] = {}; //被启发后的行访问顺序
int FQueR[] = {}; //被启发后的列访问顺序
int Value[][] = {}; //地图各点的价值因子
int QueL[] = {}; //
int QueR[] = {}; //与上面那个,是根据启发后制定的搜索顺序的行列参数
int QLen = ; //搜索队列的长度
int Ans = -; //最优解
int Count = ; //废物变量,纪念原来我错误的写法,懒得删掉了 int Swap(int *a,int *b)
{
int o=*a;
*a=*b;
*b=o;
} void Heu() //启发函数
{
for(int i=;i<=;++i){
FQueL[i] = i;
FQueR[i] = i;
} for(int i=;i<=;++i)
for(int j=;j>=i+;--j){
if(Line[FQueL[j]][] > Line[FQueL[j-]][])
Swap(&FQueL[j],&FQueL[j-]);
if(Row[FQueR[j]][] > Row[FQueR[j-]][])
Swap(&FQueR[j],&FQueR[j-]);
}
for(int i=;i<=;++i)
for(int j=;j<=;++j)
if(Map[FQueL[i]][FQueR[j]] == ){
QueL[QLen]=FQueL[i];
QueR[QLen]=FQueR[j];
QLen++;
}
// for(int i=1;i<=9;++i)
// cout<<FQueL[i]<<' '<<Line[FQueL[i]][0]<<' '<<FQueR[i]<<' '<<Row[FQueR[i]][0]<<endl;
} int belong(int i,int j) //判断行列参数为i,j的点属于哪一个九宫格。
{
int xt = ,yt = ;
for(int k=;k>=;k-=){
if(i-k>){xt=(k+)/;break;}
}
for(int k=;k>=;k-=){
if(j-k>){yt=(k+)/;break;}
}
// cout<<xt<<' '<<yt<<' '<<xt+(yt-1)*3<<endl;
// cout<<i<<' '<<j<<' '<< yt+(xt-1)*3 <<endl;
return yt+(xt-)*;
} int Score() //成绩计算
{
int Temp = ;
for(int i=;i<=;++i)
for(int j=;j<=;++j)
Temp += Map[i][j]*Value[i][j];
Ans = MAX(Temp,Ans);
// cout<<Ans<<endl;
} int Dfs(int step) //深度优先搜索主体
{
// cout<<step<<' '<<81-Count<<endl;
// for(int i=1;i<=9;++i,cout<<endl)
// for(int j=1;j<=9;++j)
// cout<<Map[i][j]<<' ';
if(step == QLen){Score();return ;}
if(!Map[QueL[step]][QueR[step]])
for(int k=;k<=;++k){
if(!Nine[belong(QueL[step],QueR[step])][k])
if(!Line[QueL[step]][k] && !Row[QueR[step]][k]){
//Heu();
// cout<<FQueL[i]<<' '<<FQueR[j]<<' '<<k<<endl;
Map[QueL[step]][QueR[step]] = k;
Nine[belong(QueL[step],QueR[step])][k] = ;
Line[QueL[step]][k]=Row[QueR[step]][k] = ;
Line[QueL[step]][]++;Row[QueR[step]][]++;
Dfs(step+);
Map[QueL[step]][QueR[step]] = ;
Nine[belong(QueL[step],QueR[step])][k] = ;
Line[QueL[step]][k]=Row[QueR[step]][k] = ;
Line[QueL[step]][]--;Row[QueR[step]][]--;
}
}
return ;
} int main()
{
for(int i=;i<=;++i)
for(int j=+(i-);j<=-(i-);++j){
Value[i][j] = +(i-);
Value[-(i-)][j] = +(i-);
Value[j][-(i-)] = +(i-);
Value[j][i] = +(i-);
} //init value 对价值表的初始,好像其他人都是直接用{}初始的.......
// for(int i=1;i<=9;++i,cout<<endl)
// for(int j=1;j<=9;++j)
// cout<<Value[i][j]<<' ';
for(int i=;i<=;++i)
for(int j=,x,y;j<=;++j){
scanf("%d",&Map[i][j]);
if(Map[i][j] != ){
Line[i][Map[i][j]] = ;
Line[i][]++;
Row[j][Map[i][j]] = ;
Row[j][]++;
Nine[belong(i,j)][Map[i][j]] = ;
Count++;
}
} // for(int i=1;i<=9;++i,cout<<endl)
// for(int j=1;j<=9;++j)
// cout<<Nine[i][j]; Heu();
Dfs(); cout<<Ans;
return ;
}
codevs1174 靶形数独的更多相关文章
- Vijos1775 CodeVS1174 NOIP2009 靶形数独
靶形数独 描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教, Z 博士拿出了他最近发 ...
- NOIP2009靶形数独[DFS 优化]
描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教,Z 博士拿出了他最近发明的“靶形数独 ...
- 靶形数独(codevs 1174)
1174 靶形数独 2009年NOIP全国联赛提高组 时间限制: 4 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Descri ...
- 洛谷 P1074 靶形数独 Label:search 不会
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...
- 【CodeVS】p1174 靶形数独
题目描述 Description 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,Z 博士 ...
- [NOIP2009] 靶形数独(搜索+剪枝)
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...
- 靶形数独 (codevs 1174)题解
[问题描述] 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,Z 博士拿出了他最近发明的“ ...
- NOIP2009 靶形数独
4.靶形数独 (sudoku.pas/c/cpp) [问题描述] 小城和小华都是热爱数学的好学生, 近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了, ...
- Luogu1074靶形数独【启发式搜索】
Luogu1074靶形数独 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, ...
随机推荐
- INT类型知多少
前言: 整型是MySQL中最常用的字段类型之一,通常用于存储整数,其中int是整型中最常用的,对于int类型你是否真正了解呢?本文会带你熟悉int类型相关知识,也会介绍其他整型字段的使用. 1.整型分 ...
- 获取openid [微信小程序]
public function wxapi(){ $data=$this->requestdata(); if(!$data['code']) exit(json_encode(array('s ...
- 题解报告:hdu 1312 Red and Black(简单dfs)
Problem Description There is a rectangular room, covered with square tiles. Each tile is colored eit ...
- 记一次java应用cpu利用率过高调试经历
1,现象 写的一个storm应用,主要是通过mysql的binlog来同步表到hbase.运行一段时间后发现,经常会出现cpu使用率飙升到200%以上,然后各种消息堆积报警等等出现各种问题 2,调研过 ...
- C#基础 结构体 枚举类型
结构体:就是一个自定义的集合,里面可以放各种类型的元素,用法大体跟集合一样. 一.定义的例子: struct student { public int nianling; public int fen ...
- 专题七:UDP编程补充——UDP广播程序的实现
一.程序实现 UDP广播程序的实现代码: using System; using System.Net; using System.Net.Sockets; using System.Text; us ...
- LN : leetcode 538 Convert BST to Greater Tree
lc 538 Convert BST to Greater Tree 538 Convert BST to Greater Tree Given a Binary Search Tree (BST), ...
- 2106. [NOIP2015] 斗地主
2106. [NOIP2015] 斗地主 ★★★☆ 输入文件:landlords.in 输出文件:landlords.out 简单对比 时间限制:2 s 内存限制:1025 M ...
- js数组的各种方法
1.检测数组 ①Instanceof: if(value instanceof Array){ } 它假定只有一个全局执行环境,若网页中包含多个框架,则存在多个不同的全局执行环境,则Instanceo ...
- Verification Mind Games---how to think like a verifier像验证工程师一样思考
1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题.具体来说,验证更加关心在严格遵循协议的基础上发现设计里面的bug,搜索corner cases,对设计的不一致要保持零容忍的态度. m ...