用二进制优化常数卡过Pku3074 Sudoku

原创 2013年12月03日 14:05:43

这道题看起来用暴力搜索似乎不可能过,但是因为二进制的运行速度实在是太快了。我们可以用二进制运算来代替布尔型的for循环枚举。这样,我们便可以节省大量时间。

我是用了l[i],h[i],kuai[i]分别代表第i列,第i行,第i块的状态,0代表未出现过,1代表已出现。

我还每次找可以填的数字最少的格子进行搜索,便把这题卡过去了。

接下来上代码:

const
 w:array[0..8,0..8]of longint=((0,0,0,1,1,1,2,2,2),
                              (0,0,0,1,1,1,2,2,2),
                              (0,0,0,1,1,1,2,2,2),
                              (3,3,3,4,4,4,5,5,5),
                              (3,3,3,4,4,4,5,5,5),
                              (3,3,3,4,4,4,5,5,5),
                              (6,6,6,7,7,7,8,8,8),
                              (6,6,6,7,7,7,8,8,8),
                              (6,6,6,7,7,7,8,8,8));
var
bb,aa:array[0..512]of longint;
a:array[0..8,0..8]of longint;
h,l,kui:array[0..8]of longint;
now,minn,x,y,ans,n,m,i,j,k:longint;
s:string;

procedure dfs(x,y:longint);
var
ii,jj,xx,yy,minn,i,j,k:longint;
begin
if (a[x,y]<>-1) then
  begin
    ans:=1;
    exit;
  end;
i:=1;
j:=l[y] or h[x] or kui[w[x,y]];
if j=511 then
  exit;
while i<512 do
begin
     if j or i<>j then
             begin
               l[y]:=l[y] or i;
               h[x]:=h[x] or i;
               kui[w[x,y]]:=kui[w[x,y]]or i;
               a[x,y]:=bb[i];
               minn:=16;
               xx:=0;yy:=0;
               ii:=0;
               while ii<=8 do
                begin
                 for jj:=0 to 8 do
                   if a[ii,jj]=-1 then
                    begin
                      k:=l[jj] or h[ii] or kui[w[ii,jj]];
                      if aa[k]<minn then
                        begin
                          minn:=aa[k];
                          xx:=ii; yy:=jj;
                        end;
                      if minn=1 then
                         begin
                           ii:=9;
                           break;
                         end;
                    end;
                    inc(ii);
                 end;
               dfs(xx,yy);
               if ans<>0 then
                 exit;
               l[y]:=l[y] and (not i);
               h[x]:=h[x] and (not i);
               kui[w[x,y]]:=kui[w[x,y]] and (not i);
             end;
           i:=i<<1;
end;
a[x,y]:=-1;
end;

begin
bb[1]:=0; bb[2]:=1; bb[4]:=2; bb[8]:=3; bb[16]:=4;
bb[32]:=5; bb[64]:=6; bb[128]:=7;bb[256]:=8;
for k:=0 to 512 do
  begin
          now:=0;
          if k or 1<>k then
            inc(now);
          if k or 2<>k then
            inc(now);
          if k or 4<>k then
            inc(now);
          if k or 8<>k then
            inc(now);
          if k or 16<>k then
            inc(now);
          if k or 32<>k then
            inc(now);
          if k or 64<>k then
            inc(now);
          if k or 128<>k then
            inc(now);
          if k or 256<>k then
            inc(now);
          aa[k]:=now;
  end;
while not eof do
  begin
    fillchar(h,sizeof(h),0);
    fillchar(l,sizeof(l),0);
    fillchar(kui,sizeof(kui),0);
    fillchar(a,sizeof(a),$ff);
    readln(s);    ans:=0;
    if s[1]='e' then
      break;
    for i:=0 to 80 do
      if  s[i+1]<>'.' then
        begin
          j:=ord(s[i+1])-ord('1');
          a[i div 9,i mod 9]:=j;
          h[i div 9]:=h[i div 9] or (1<<j);
          l[i mod 9]:=l[i mod 9] or (1<<j);
          kui[w[i div 9,i mod 9]]:=kui[w[i div 9,i mod 9]] or(1<<j);
        end;
    minn:=16;
    i:=0;
    while i<=8 do
      begin
      for j:=0 to 8 do
        if a[i,j]=-1 then
        begin
          k:=l[j] or h[i] or kui[w[i,j]];
          if aa[k]<minn then
            begin
              minn:=aa[k];
              x:=i; y:=j;
            end;
          if minn=1 then
            begin
              i:=9;
              break;
            end;
        end;
        inc(i);
      end;
    dfs(x,y);
    for i:=0 to 8 do
      begin
        for j:=0 to 8 do
          write(a[i,j]+1);
      end;
    writeln;
  end;
end.
版权声明:博主有些地方可能有些表达欠缺,希望大家能多给些建议,也希望和大家一起讨论问题,请多多留言

【uoj#150】【NOIP2015】运输计划 树上前缀和+lca+二分+拓扑排序+特别的卡常数技巧

公元 2044 年,人类进入了宇宙纪元。L 国有 nn 个星球,还有 n−1n−1 条双向航道,每条航道建立在两个星球之间,这 n−1n−1 条航道连通了 LL 国的所有星球。小 P 掌管一家物流公司...
  • LOI_DQS
  • LOI_DQS
  • 2016年03月08日 21:03
  • 1572

NYOJ 654 喜欢玩warcraft的ltl (01背包常数优化)

【题目链接】:click here~~ 一个常数优化 前面的伪代码中有 for v=V..1,可以将这个循环的下限进行改进。 由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w[n...
  • u013050857
  • u013050857
  • 2015年09月09日 09:30
  • 1076

关于如何减小线段树常数

以前写线段树常数巨大,因为懒所以一直没改,今天终于下定决心把线段树常数调小 0.位运算,前置技能 1.非递归是一定要有的,以前觉得非递归特别特别麻烦,今天写了一下发现比递归好写 2.不要一直改变...
  • lcrtest
  • lcrtest
  • 2016年03月07日 13:22
  • 810

NOIP卡常数技巧

摘自某位大佬的博客(http://www.cnblogs.com/widerg/p/7353866.html) 1.IO优化 fread 和 fwrite ,如果还想再优化有mmap….(然而并不...
  • a1351937368
  • a1351937368
  • 2017年10月05日 17:47
  • 1024

C语言数值常数

0UL 表示 无符号长整型 0 1UL 表示 无符号长整型 1 如果不写UL后缀,系统默认为:int, 即,有符号整数。1.数值常数有:整型常数、浮点常数; 2.只有数值常数才有后缀说明; 3.数值...
  • skyie53101517
  • skyie53101517
  • 2015年09月02日 16:07
  • 821

CF 86D 莫队(卡常数)

CF 86D 题目链接: http://codeforces.com/problemset/problem/86/D 题意: 一个数列,问[L,R]区间内(每个数字的个数的平方*数字的大小)的...
  • beihai2013
  • beihai2013
  • 2016年01月25日 13:14
  • 447

01背包(降维 + 常数级优化)

题目:    共n个物体,第i个重量为w[i],价值v[i],背包最多能背不超过W的物体,求最大的价值分析:    每个物体只有一个,在容量允许时(W>w[i]),则对于每个物体只有取、不取两种选择 ...
  • u014561729
  • u014561729
  • 2014年07月17日 15:12
  • 290

多重背包二进制优化的思考

其实说白了我们最朴素的多重背包做法是将有数量限制的相同物品看成多个不同的0-1背包。这样的时间复杂度为O(V*Σn(i)) V为空间容量,n(i)为每种背包的数量限制。如果这样会超时,我们就得考虑更优...
  • xky0714
  • xky0714
  • 2013年08月19日 22:36
  • 1079

多重背包二进制分解思想讲解

转载自 在背包九讲里面将多重背包转化为01背包,并且进行时间优化,有利用到一个二进制分解的思想。 下面是在网上搜索之后得到的一个关于二进制分解思想的讲解和实现 多重背包二进制分解思想...
  • weinierzui
  • weinierzui
  • 2014年04月14日 12:59
  • 3231

信息学竞赛的常数优化、常见问题、代码风格等

如果编译器没有开O2优化 用库函数常数会凭空增加很多。。 似乎NOIP考场不开O2 某些时候,如果你优化到无法再优化的时候 尝试去自己重新实现库函数。比如 isdigit() max()/mi...
  • qq_33583069
  • qq_33583069
  • 2016年11月08日 20:14
  • 1364
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用二进制优化常数卡过Pku3074 Sudoku
举报原因:
原因补充:

(最多只允许输入30个字)