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个相同决策,其余两端决策数会依次递减,均摊69(我估计的,这也可以接受)而实际上非常小,通常由于唯一解,第一次就会直接搜到答案。

贴代码

#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;}
0 0
原创粉丝点击