题目传送

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

联想人做数独的策略,总是先填可填数最少的那个空,再填选择第二少的。。。其实这种策略就造就了一个深度浅时分支也较少的搜索树。合适的搜索顺序再配合剪枝==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. Arm-linux-gcc-4.3.2安装步骤 (转)

    http://blog.chinaunix.net/uid-26119896-id-3302233.html 安装交叉编译工具链: 1.首先以root用户登入 2.复制arm-linux-gcc-4. ...

  2. Java中字母大小写的转换

    例:String str = "AbC"; 把字符串所有字母变成小写: System.out.println(str.toLowerCase()); 把字符串所有字母大写: Sys ...

  3. 书籍:wpf学习书籍介绍

    WPF参考书推荐 下面先整理下,本人主要学习的WPF参考书: 1.WPF编程宝典(C#2010) 该书:(必读) 心得体会:读完该书后,你对WPF的基础和基本控件的使用,包括WPF的编程模型,相比Wi ...

  4. 1000行基本SQL

    /* Windows服务 */ -- 启动MySQL net start mysql -- 创建Windows服务 sc create mysql binPath= mysqld_bin_path(注 ...

  5. Java数据结构之算法时间度

    1.度量一个程序(算法)执行时间的两种方法 1)事后统计的方法 这种方法可行, 但是有两个问题:一是要想对设计的算法的运行性能进行评测,需要实际运行该程序:二是所得时间的统计量依赖于计算机的硬件.软件 ...

  6. 几个 BeanUtils 中的坑,千万别踩!

    背景 最近项目中在和第三方进行联调一个接口,我们这边发送http请求给对方,然后接收对方的回应,代码都是老代码. 根据注释,对方的SDK中写好的Request类有一个无法序列化的bug,所以这边重新写 ...

  7. 补充[BNDSOJ]小p的数列

    强烈安利gjz的题解,看一遍即可ac:传送门 进入重点: 为啥$to=(dp[i][k][ii]+dp[k+1][j][jj])/2$ 位运算重点:a&b=a+b-a|b 为啥呢? 例子: a ...

  8. C语言数组名取地址。。。

    int main(){ int a[5] = { 1, 2, 3, 4, 5 }; printf("%08X ,%08X ,%08X ,%08X", a, &a, a + ...

  9. Prometheus 2.14.0 新特性

    Prometheus 2.14.0 现在(2019.11.11)已经发布,在上个月的 2.13.0 之后又进行了一些修正和改进. 这次最大的新功能是基于 React 的新 UI,与现有 UI 大体相同 ...

  10. ubuntu系统更新命令

    一.图形界面更新升级 1.点击”系统设置“,打开“软件和更新”,切到“更新”栏目进行更新设置. 2.可以通过软件更新器进行更新升级自己想要更新的 二.命令方式更新升级 1.先解锁 ps -e|grep ...