GDOI2016模拟8.21新数独
来源:互联网 发布:ajax json 提交 java 编辑:程序博客网 时间:2024/06/05 20:53
题目
下面是一个没有数字,只有大小关系(没错!那些尖角都是“大于”符号!)的数独:
除了大小关系外(注意相邻格子不能相同),还需要满足通常的数独规则:
l 每个格子都是1~9 的数字
l 每行都是1~9的排列
l 每列都是1~9的排列
l 每个3*3的子矩阵(上图中用粗线隔开,一共有3*3个这样的子矩阵)都是1~9的排列
为了美观,每个3*3子矩阵的所有12对相邻格子的大小关系都将给出。
这道题,我们可以注意到有朴素数独的限制,例如每行都是1~9的排列
, 每列都是1~9的排列,但光有这个,搜索还是很慢。
这里,我打算所以一下一开始做题时我对这道题的看法:
那些大于小于号,假设我们现在要确定9要放哪里,那么画出来的图,对应9的位置,所有符号都是它指向外面的(就是它周围的都是他指向外面的大于号),这简直是9在大吼着:“我在这里…”…于是我就顺从了..
对于这个发现,我们可以从大到小枚举先放哪些数,放完9个位置后再放其他的,若存在a<b,则b连a一条边,并将a入度+1。由于我们每次放的都是现存最大的数,那么我们按小九宫格为单位,每个九宫格里找到入度为0的位置,将数填进去,然后消除该位置对周围位置的影响(类似拓扑排序,将它连出去的位置入度-1)。
加上这个优化,我们就可以飞快的跑过了….(说实话,刚提交代码,连running都没有看到..)
好了,我们来讨论一下为甚么这个剪枝这么强力?
由于保证存在唯一解,对于相同决策,即同一个数(指一个小九宫格内)能填的位置(入度为0)的地方不会超过5,而当你选择了一个位置填入的时候,说明你周围的位置都是先前不可能决策到的(这个可以证明前者),而当前存在多个决策时,则说明以后的决策会少那么多(我们可以想着一个正向决策即由大取到小,一个反向决策即由小取到大)【而且加上数独的限制,均摊相同决策不超过3个】均摊下来,若要跑得最慢的话,最大决策层在中间,只会有3个相同决策,其余两端决策数会依次递减,均摊
贴代码
#include<iostream>#include<cstdio>#include<algorithm>#define N 10using namespace std;int in[82],g[82],a[1000][2],d[82],help[N],b[N];bool bzh[9][9],bzz[9][9];void ins(int x,int y){ static int sum=0; a[++sum][0]=y,a[sum][1]=g[x],g[x]=sum;}void did1(int x){ static char c; for (int j=1;j<=3;j++){ for (int k=1;k<=2;k++){ scanf(" %c",&c); if (c=='>') in[x+1]++,ins(x,x+1); else in[x]++,ins(x+1,x); x++; } x++; }}void did2(int x){ static char c; for (int j=1;j<=3;j++) for (int k=1;k<=3;k++){ scanf(" %c",&c); if (c=='v') in[x]++,ins(x-9,x); else in[x-9]++,ins(x,x-9); x++; }}void init(){ static int x; for (int i=1;i<=3;i++){ x=(i-1)*27+1; did1(x); x+=9; did2(x); did1(x); x+=9; did2(x); did1(x); }}int did(int x){ return !x?9:x;}bool jian(int x,int y){ return !bzz[x][did(y%9)]&&!bzh[x][y/9+(y%9>0)];}void change(int x,int y){ bzz[x][did(y%9)]=bzh[x][y/9+(y%9>0)]=1; for (int i=g[y];i;i=a[i][1]) in[a[i][0]]--;}void changeback(int x,int y){ bzz[x][did(y%9)]=bzh[x][y/9+(y%9>0)]=0; for (int i=g[y];i;i=a[i][1]) in[a[i][0]]++;}bool dfs(int x,int y){ int s; if (x>9){ x=1,y--; } if (!y)return 1; s=help[x]; ++x; for (int i=1;i<=9;i++) if (!d[s+b[i]]&&jian(y,s+b[i])&&!in[s+b[i]]){ d[s+b[i]]=y; change(y,s+b[i]); if (dfs(x,y))return 1; changeback(y,s+b[i]); d[s+b[i]]=0; } return 0;}void work(){ help[1]=1,help[2]=4,help[3]=7,help[4]=28,help[5]=31,help[6]=34,help[7]=55,help[8]=58,help[9]=61; b[2]=1,b[3]=2,b[4]=9,b[5]=10,b[6]=11,b[7]=18,b[8]=19,b[9]=20; dfs(1,9);}void write(){ for (int i=1;i<=81;i++){ if (!(i%9))printf("%d\n",d[i]); else printf("%d ",d[i]); }}int main(){ init(); work(); write(); return 0;}
- GDOI2016模拟8.21新数独
- GDOI2016模拟8.21总结
- GDOI2016模拟8.21新Nim游戏
- GDOI2016模拟8.10踢足球
- GDOI2016模拟8.8旋转
- GDOI2016模拟8.8处理器
- GDOI2016模拟8.13总结
- GDOI2016模拟8.14总结
- GDOI2016模拟8.14数树数
- GDOI2016模拟8.15总结
- GDOI2016模拟8.15蜘蛛侠
- GDOI2016模拟8.15送票
- GDOI2016模拟8.16总结
- GDOI2016模拟8.16帮派
- GDOI2016模拟8.18总结
- GDOI2016模拟8.18蜡笔
- GDOI2016模拟8.18的士
- GDOI2016模拟8.18解密
- [HTML] CSS 下拉列表菜单
- hdu 5416 CRB and Tree(暴力)
- C# Entity Framework MySql CodeFirst
- hdu 5316 Magician 2015 Multi-University Training Contest 3
- 2015/08/21
- GDOI2016模拟8.21新数独
- JAVA中关于servlet的工作原理
- hibernate简单实例
- 输出有序数组的连续序列范围
- linux下50个常用命令
- [c] sdnuoj1147Pythagoras's Revenge
- hdoj-2066 一个人的旅行【最短路径--dijkstra&&spfa&&floyd】
- C# LinkedList<T> 泛型类的实现
- FZU 2135 数字游戏