题目传送

主要是搜索顺序不同导致效率千差万别。

联想人做数独的策略,总是先填可填数最少的那个空,再填选择第二少的。。。其实这种策略就造就了一个深度浅时分支也较少的搜索树。合适的搜索顺序再配合剪枝==AC。

所以搜索顺序为:从当前可填数的数目最少的那个空开始。注意:每填一个空,都会导致同行同列同九宫格的空的可填数数目减一,所以不能一开始就排序。(实测这样做会比正解慢8倍左右,真是恐怖如斯)所以要在分支选择时去找。为了平衡准确性与高效性,可以用一个简单的判断找到一个比较合适的空去填(因为如果每次都精确去找那个可填数数目最小的那个空会导致复杂度偏高,因此只要简单地找到可填数数目相对小的那个空就行)。

找一下搜索面临或有关的状态与维度:当前分数v,当前要填的点的坐标,填了t个点,总共要填cnt个点,各行各列各九宫格填数情况。

可行性剪枝考虑:

  发现一个有趣的性质:数独中每一行都会有1到9各出现一次,共有9行,所以1到9每个数到最后必定出现9次,所以可以设一个used[]数组记录数出现的次数,若小于0,肯定不是正解,回溯,故每次填空要用不仅usedi大于0且i在同行同列同九宫格都没有出现过的i。

最优性剪枝:

  可以将所有空能填的最大的数*该空的分数求和得到一个还能得到的至多的分数zhiduo,填空时,若发现v+zhiduo还<=已搜到的答案ans,显然不会使答案更优,所以回溯;同时每填一个空都更新一下zhiduo,回溯时也要照顾到zhiduo。

AC代码:

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm> using namespace std; int a[][],fen[][],cnt,zhiduo,m[][],ans;//第二下标: 0:纵坐标;1:横坐标 先纵再横
int ma[][],used[];
int h[],l[],maxh,maxl;//某行、列已经填了几个数 bool hang[][],lie[][],jiu[][][];//行、列、九宫格的填数情况 void init()
{
for(int i=;i<=;i++) used[i]=;
for(int f=;f<=;f++)//初始化每个空的分数,不懂的可以拿纸笔自己模拟一下
{
for(int i=f-;i<=-f+;i++) fen[f-][i]=fen[-f+][i]=f;
for(int j=f-+;j<=-f+-;j++) fen[j][f-]=fen[j][-f+]=f;
}
} void dfs(int k,int v,int x,int y)//要填第k个,当前分数v,当前填的空的纵、横坐标。
{
if(v+zhiduo<=ans) return;//最优性剪枝
for(int i=;i<=;i++)//填哪个数
{
if(used[i]&&(!hang[x][i])&&(!lie[y][i])&&(!jiu[x/][y/][i]))//可行性剪枝
{
v+=fen[x][y]*i;
if(k!=cnt)
{
used[i]--;
hang[x][i]=;lie[y][i]=;jiu[x/][y/][i]=;
h[x]++;l[y]++;
zhiduo-=fen[x][y]*ma[x][y];
maxh=maxl=;
a[x][y]=i;
for(int i=;i<=;i++) if(h[i]!=&&h[i]>h[maxh]) maxh=i;//找接下来要填的空
for(int i=;i<=;i++) if(!a[maxh][i]&&l[i]!=&&l[i]>l[maxl]) maxl=i;
dfs(k+,v,maxh,maxl);
hang[x][i]=;lie[y][i]=;jiu[x/][y/][i]=;//回溯的时候少一个都会wa啊
zhiduo+=fen[x][y]*ma[x][y];
h[x]--;l[y]--;
a[x][y]=;
used[i]++;
}
else
ans=max(ans,v);
v-=fen[x][y]*i;
}
}
} int main()
{
init();
int v=;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j])
{
used[a[i][j]]--;
h[i]++;
l[j]++;
if(hang[i][a[i][j]]||lie[j][a[i][j]]||jiu[i/][j/][a[i][j]])
{
cout<<-;
return ;
}
hang[i][a[i][j]]=;
lie[j][a[i][j]]=;
jiu[i/][j/][a[i][j]]=;
v+=fen[i][j]*a[i][j];
}
else
cnt++;
}
int most;
for(int i=;i<=;i++)//求起始时的至多zhiduo
for(int j=;j<=;j++)
if(!a[i][j])
{
most=;
while(hang[i][most]||lie[j][most]||jiu[i/][j/][most]) most--;
ma[i][j]=most;//空(j,i)能填的最大的数
zhiduo+=most*fen[i][j];
}
h[]=-;
l[]=-;
maxh=,maxl=;
for(int i=;i<=;i++)//找一开始要填的空
if(h[i]!=&&h[i]>h[maxh]) maxh=i;
for(int i=;i<=;i++)
if(!a[maxh][i]&&l[i]!=&&l[i]>l[maxl]) maxl=i;
dfs(,v,maxh,maxl);
if(!ans) ans=-;
cout<<ans;
return ;
}

一本通&&洛谷 ——靶型数独——题解的更多相关文章

  1. 洛谷P2832 行路难 分析+题解代码【玄学最短路】

    洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...

  2. 【洛谷P3960】列队题解

    [洛谷P3960]列队题解 题目链接 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m ...

  3. 洛谷P2312 解方程题解

    洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...

  4. 洛谷P1577 切绳子题解

    洛谷P1577 切绳子题解 题目描述 有N条绳子,它们的长度分别为Li.如果从它们中切割出K条长度相同的 绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位(直接舍掉2为后的小数). 输入输出格 ...

  5. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  6. 洛谷 P1220 关路灯 题解

    Description 有 $n$ 盏路灯,每盏路灯有坐标(单位 $m$)和功率(单位 $J$).从第 $c$ 盏路灯开始,可以向左或向右关闭路灯.速度是 $1m/s$.求所有路灯的最少耗电.输入保证 ...

  7. 【洛谷P3410】拍照题解(最大权闭合子图总结)

    题目描述 小B有n个下属,现小B要带着一些下属让别人拍照. 有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影.如果这一些人没带齐那么就不能拍照,小B也不会得到钱. 注意:带下属不是白带的 ...

  8. [BZOJ 3039&洛谷P4147]玉蟾宫 题解(单调栈)

    [BZOJ 3039&洛谷P4147]玉蟾宫 Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地. ...

  9. 洛谷P1074 靶形数独 [搜索]

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

随机推荐

  1. IP地址相关运算(如VLSM,超网汇总)

    1.根据IP地址+子网掩码算出IP地址所在的网段(网络号) 例子: IP地址192.168.10.33,子网掩码为:255.255.255.240 (/28) ,写出所在的网络号 1.得出子网的块大小 ...

  2. Linux运维的第三周总结

    01. 下列文件中, 包含了主机名到IP地址的映射关系的文件是()       A. /etc/HOSTNAME    B. /etc/hosts    C. /etc/resolv.conf    ...

  3. 图——图的Prim法最小生成树实现

    1,运营商的挑战: 1,在下图标出的城市间架设一条通信线路: 2,要求: 1,任意两个城市间都能够通信: 2,将架设成本降至最低: 2,问题抽象: 1,如何在图中选择 n - 1 条边使得 n 个顶点 ...

  4. 通过编写串口助手工具学习MFC过程——(二)通过“打开串口”按钮了解基本操作

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  5. vscode学习(三)之如何修改打开终端的默认shell

    实现 第一步:打开VSCode的设置(Preferences>User Settings) 第二步:搜索terminal.integrated.shell.osx 的 并把它的值改为你的zsh安 ...

  6. windows 桌面背景设置实例

    应用SystemParametersInfo函数可以获取和设置数量众多的windows系统参数.这个小程序就是运用了SystemParametersInfo函数来设置桌面的墙纸背景,而且程序可以让我们 ...

  7. vuex实现数据共享

    1.store.js结构 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Sto ...

  8. ## ucore Lab0 一些杂记

    ucore Lab0 一些杂记 前一阵子开始做 MIT 6.828,做了两三个实验才发现清华的 ucore 貌似更友好一些,再加上前几个实验也与6.828 有所重叠,于是决定迁移阵地. 文章计划分两类 ...

  9. Django中利用type动态操作数据库表

    场景分析: 后台MySql数据库保存了一大批按股票代码命名的数据表,每张表保存的是每只股票的日线数据. stock_000002 stock_600030 stock_600020 ...一共3000 ...

  10. #pragma 的使用(转)

    尽管 C 和 C++ 都已经有标准,但是几乎每个编译器 (广义,包含连接器等) 扩展一些 C/C++ 关键字. 合理地应用这些关键字,有时候能使我们的工作非常方便.下面随便说说 Visual C++ ...