usaco 1.4 clocks 2008.11.5

本文探讨USACO 2008年11月赛题Clocks的两种解法:宽度优先搜索(宽搜)及九重循环枚举。宽度优先搜索虽能解决问题但受限于数据规模易导致溢出;而九重循环枚举通过利用操作周期性,有效减少状态空间,实现简洁高效的解决方案。

usaco 1.4 clocks 2008.11.5

小结

1.clocks-宽搜.pas  宽搜,只过了两组,就溢出了,本来想开大一点队列,但占用的空间太多,超出了测试的要求,又看到网上的人也用的宽搜,也是只过了两组,就放弃了宽搜。

2.clocks-meiju.pas  然后看到了网上的结题报告,如下:由于操作4次等于没操作,所以只用枚举操作0次到操作3次这几种情况,枚举此时在最差情况下也只有4^9次,可以接受,然后就编了个9重循环,ac了。只是要的打字比较多,数组也不能做循环变量

program1:宽搜2

{
ID:  
PROG: clocks
LANG: PASCAL
}
program p_clocks;
const
  maxx=10000;
  maxn=300;
  fin='clocks.in';fout='clocks.out';
  a:array[1..9,0..5]of integer=
         ((4,1,2,4,5,0),(3,1,2,3,0,0),(4,2,3,5,6,0),
          (3,1,4,7,0,0),(5,2,4,5,6,8),(3,3,6,9,0,0),
          (4,4,5,7,8,0),(3,7,8,9,0,0),(4,5,6,8,9,0));

type
  arr=array[1..9]of integer;
  arr2=array[0..maxn]of integer;
  code=record
       m:arr;
       v:arr2;
       end;
var
  y:array[1..maxx]of code;
  p:arr;
  r,g:arr2;
  f1,f2:text;
  i,x:integer;
  f:array[0..3,0..3,0..3,0..3,0..3,0..3,0..3,0..3,0..3]of boolean;
     procedure init;
     var i,k:integer;

     begin
        assign(f1,fin);reset(f1);
        assign(f2,fout);rewrite(f2);
         for i:=1 to 9 do
               begin read(f1,p[i]);k:=(p[i] div 3)mod 4;p[i]:=k; end;
     end;
     procedure deal;
     var i,u,j:integer;c:arr;s:arr2;
     begin
     u:=0;
     repeat inc(u);
         for i:=1 to 9 do
            begin
                c:=y[u].m;s:=y[u].v;
                for j:=1 to a[i,0] do
                     c[a[i,j]]:=(c[a[i,j]]+1)mod 4;
                inc(s[0]);s[s[0]]:=i;
                if c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]+c[8]+c[9]=0 then
                    begin g:=s;exit;end else
                       if f[c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9]] then
                          begin inc(x);y[x mod maxx].m:=c;y[x mod maxx].v:=s;
                              f[c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9]]:=false;
                            end;
           end;
      until u>=x;
      end;
     {-------------main--------------}
     begin
         fillchar(f,sizeof(f),true);
       init;
       fillchar(r,sizeof(r),0);
       x:=1;y[1].m:=p;y[1].v:=r;
       deal;
       for i:=1 to g[0]-1 do
         write(f2,g[i],' ');
         writeln(f2,g[g[0]]);
        close(f1);
        close(f2);
      end.

program2:九重循环:有时枚举也是不错的方法。

{
ID: 
PROG: clocks
LANG: PASCAL
}
{}
program p_clock_meiju;
  const
  fin='clocks.in';fout='clocks.out';
  a:array[1..9,0..5]of integer=
         ((4,1,2,4,5,0),(3,1,2,3,0,0),(4,2,3,5,6,0),
          (3,1,4,7,0,0),(5,2,4,5,6,8),(3,3,6,9,0,0),
          (4,4,5,7,8,0),(3,7,8,9,0,0),(4,5,6,8,9,0));
  type
     arr=array[1..9]of integer;
  var
  f1,f2:text;
  p,e:arr;
  g:array[1..30]of longint;
  g1,i,j,t1,t2,t3,t4,t5,t6,t7,t8,t9:integer;
  procedure init;
     var i,k:integer;
     begin
        assign(f1,fin);reset(f1);
        assign(f2,fout);rewrite(f2);
        for i:=1 to 9 do
           begin read(f1,p[i]);k:=(p[i] div 3)mod 4;p[i]:=k;end;
     end;
procedure print;
begin
  g1:=0;
  while t1<>0 do
     begin dec(t1);inc(g1);g[g1]:=1;end;
    while t2<>0 do
     begin dec(t2);inc(g1);g[g1]:=2;end;
    while t3<>0 do
     begin dec(t3);inc(g1);g[g1]:=3;end;
     while t4<>0 do
     begin dec(t4);inc(g1);g[g1]:=4;end;
      while t5<>0 do
     begin dec(t5);inc(g1);g[g1]:=5;end;
       while t6<>0 do
     begin dec(t6);inc(g1);g[g1]:=6;end;
       while t7<>0 do
     begin dec(t7);inc(g1);g[g1]:=7;end;
       while t8<>0 do
     begin dec(t8);inc(g1);g[g1]:=8;end;
       while t9<>0 do
     begin dec(t9);inc(g1);g[g1]:=9;end;
     for i:=1 to g1-1 do write(f2,g[i],' ');
     writeln(f2,g[g1]);
     end;

procedure doit;
var u,k,w:integer;
  begin
     for t1:=0 to 3 do
       for t2:=0 to 3 do
         for t3:=0 to 3 do
           for t4:=0 to 3 do
             for t5:=0 to 3 do
               for t6:=0 to 3 do
                 for t7:=0 to 3 do
                   for t8:=0 to 3 do
                     for t9:=0 to 3 do
                         begin e:=p;
                            for k:=1 to a[1,0] do
                                  e[a[1,k]]:=e[a[1,k]]+t1;
                             for k:=1 to a[2,0] do
                                       e[a[2,k]]:=e[a[2,k]]+t2;
                             for k:=1 to a[3,0] do
                                     e[a[3,k]]:=e[a[3,k]]+t3;
                               for k:=1 to a[4,0] do
                                     e[a[4,k]]:=e[a[4,k]]+t4;
                                for k:=1 to a[5,0] do
                                    e[a[5,k]]:=e[a[5,k]]+t5;
                                 for k:=1 to a[6,0] do
                                    e[a[6,k]]:=e[a[6,k]]+t6;
                                 for k:=1 to a[7,0] do
                                    e[a[7,k]]:=e[a[7,k]]+t7;
                                  for k:=1 to a[8,0] do
                                     e[a[8,k]]:=e[a[8,k]]+t8;
                                  for k:=1 to a[9,0] do
                                    e[a[9,k]]:=e[a[9,k]]+t9;
                                   u:=0;
                            for j:=1 to 9 do
                                 begin
                                    w:=e[j] mod 4;
                                    e[j]:=w;
                                    inc(u,e[j]);
                                 end;
                             if u=0 then begin print;exit;end;
                         end;
     end;
     {--------------main----------------}
     begin
       init;
       doit;
       close(f1);
       close(f2);
     end.

data

------- test 1 -------

9 9 12

6 6 6

6 3 6

------- test 2 -------

12 9 12

9 9 9

12 9 12

------- test 3 -------

6 9 3

3 3 9

12 12 12

------- test 4 -------

9 3 9

9 9 9

9 9 9

------- test 5 -------

6 12 12

12 12 12

12 12 12

------- test 6 -------

3 12 9

6 6 6

12 12 12

------- test 7 -------

12 3 3

3 6 6

12 3 6

------- test 8 -------

12 3 9

9 12 12

3 6 9

------- test 9 -------

9 12 9

12 3 12

9 12 9

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值