【USACO题库】1.4.2 The Clocks时钟.TJ

标题的简介:
【USACO题库】1.4.2 The Clocks——Tj

https://jzoj.net/junior/#contest/show/1232/11(下文题目描述还是原地址清楚)
考虑将如此安排在一个 3 x3 行列中的九个时钟:
|-------| |-------| |-------|

| | | | | | |

|—O | |—O | | O |

| | | | |

|--------| |-------| |-------|

A            B            C

|-------| |-------| |-------|

| | | | | |

| O | | O | | O |

| | | | | | | | |

|-------| |-------| |-------|

D            E            F

|-------| |-------| |-------|

| | | | | |

| O | | O—| | O |

| | | | | | | |

|-------| |-------| |-------|

G            H            I

目标要找一个最小的移动顺序次将所有的指针指向12点。
下面原表格列出了9种不同的旋转指针的方法,每一种方法都叫一次移动。
选择1到9号移动方法,将会使在表格中对应的时钟的指针顺时针旋转90度。
移动方法 受影响的时钟


1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI


Example
9 9 12 9 12 12 9 12 12 12 12 12 12 12 12
6 6 6 5 -> 9 9 9 8-> 9 9 9 4 -> 12 9 9 9-> 12 12 12
6 3 6 6 6 6 9 9 9 12 9 9 12 12 12
[但这可能不是正确的方法,请看下面]
PROGRAM NAME: clocks
INPUT FORMAT
第1-3行: 三个空格分开的数字,每个数字表示一个时钟的初始时间,3,6,9,12。
数字的含意和上面第一个例子一样。
SAMPLE INPUT (file clocks.in)
9 9 12
6 6 6
6 3 6
OUTPUT FORMAT
单独的一行包括一个用空格分开的将所有指针指向12:00的最短移动顺序的列表。
如果有多种方案,输出那种使的连接起来数字最小的方案。(举例来说5 2 4 6 < 9 3 1 1)。
SAMPLE OUTPUT (file clocks.out)
4 5 8 9
简单来说就是有9个钟,编号为a~i。你要把他的所有的钟指针改成12点,当然有4钟指针方案:3点、6点、9点、12点四种方案。按照:
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
这9种方案的方法来改变,比如第一种方案就是编号为A\B\D\E四个钟面的数加3.
此题很有含金量,所以来讲一讲。
就是用宽搜的方法去枚举每一个方案,然而会超时或空间炸掉。所以说一说优化:
优化1:空间与时间的压缩:一般我们都会用一个1到9的数组来储存每个钟面,然后判断各个钟面是不是12点时,就会发现时间瞬间变成了9倍而且空间也十分大。用一个丧心病狂的方法,把每个数字改掉,12点改成4点,9点改成3点,6点改成2点,3点改成1点。例如输入时为
9 9 12
6 6 6
6 3 6
原来的记录数组就是:9,9,12,6,6,6,6,3,6.变成:3,3,4,2,2,2,2,1,2.
见证奇迹,把9个数改成9位数,用一个longint来记录:334222212,空间减少9倍,比较时就比较334222212等不等于444444444就OK,时间减少9倍。没算错的话是50分左右,下一个优化。
优化2:对下面一个优化有用,看起来没用,但是很有用。我们发现,输出答案都是从小到大的方案。完
优化3:因为输出答案从小到大,我们细心点就发现:每个方案最多用3次,因为用4次是没有意义的。所以我们就每个方案循环3次,就不理了。这两个优化看起来没有屁用,但是实际上这两个优化才是ac的关键之处,可以省x倍(什么鬼)
程序参考:

type
        new=record
                s:string;
                b:array[1..9] of boolean;
                a:longint;
        end;

var
        fx:array[1..9,1..5] of longint=((1,2,4,5,0),(1,2,3,0,0),(2,3,5,6,0),(1,4,7,0,0),(2,4,5,6,8),(3,6,9,0,0),(4,5,7,8,0),(7,8,9,0,0),(5,6,8,9,0));
        z:array[1..3,1..9] of longint=((100000000,10000000,1000000,100000,10000,1000,100,10,1),(200000000,20000000,2000000,200000,20000,2000,200,20,2),(300000000,30000000,3000000,300000,30000,3000,300,30,3));
        a:array[1..300000] of new;
        b:array[1..3,1..3] of longint;
        i,j,k,l,n,m,p1,p2,p3,ed:longint;

procedure dg(dep:longint);
var
        i,j,k,l,n,m,y:longint;
        t:new;
        bz,bz1:boolean;
        s1:string;
begin
        bz:=true;
        t.a:=a[dep].a;
        fillchar(t.b,sizeof(t.b),true);
        for i:=9 downto 1 do
                if a[dep].b[i]=false then
                begin
                        bz:=false;
                        break;
                end;
        if bz=true then i:=0;
        for j:=i+1 to 9 do
        begin
                for n:=1 to 3 do
                begin
                        t.a:=a[dep].a;
                        for l:=1 to 5 do
                        begin
                                if fx[j,l]<>0 then
                                begin
                                        k:=t.a div z[1,fx[j,l]] mod 10;
                                        k:=k+n;
                                        if k>4 then
                                        begin
                                                y:=k mod 4;
                                                t.a:=t.a-z[1,fx[j,l]]*(k-n)+z[1,fx[j,l]]*y;
                                        end
                                        else t.a:=t.a+z[n,fx[j,l]];
                                end;
                        end;
                        bz1:=true;
                        if t.a<>444444444 then
                        begin
                                bz1:=false;
                        end;
                        if bz1=true then
                        begin
                                s1:=a[dep].s;
                                for l:=1 to n do
                                s1:=s1+chr(j+48);
                                for l:=1 to length(s1) do
                                        write(s1[l],' ');
                                writeln;

                                halt;
                        end
                        else
                        begin
                                //if bz=true then
                                begin
                                        inc(p3);
                                        a[p3].a:=t.a;
                                        for l:=1 to 9 do
                                        a[p3].b[l]:=a[dep].b[l];
                                        a[p3].b[j]:=false;
                                        a[p3].s:=a[dep].s;
                                        for l:=1 to n do
                                        a[p3].s:=a[p3].s+chr(j+48);
                                end;
                        end;
                end;
        end;
end;

begin
        for i:=1 to 3 do
                for j:=1 to 3 do
                begin
                        inc(m);
                        read(b[i,j]);
                        if b[i,j]=3 then
                                a[1].a:=a[1].a*10+1;
                        if b[i,j]=6 then
                                a[1].a:=a[1].a*10+2;
                        if b[i,j]=9 then
                                a[1].a:=a[1].a*10+3;
                        if b[i,j]=12 then
                                a[1].a:=a[1].a*10+4;

                                a[1].b[m]:=true;
                end;
         p1:=1;p2:=1;p3:=1;
        repeat
                for i:=p1 to p2 do
                        dg(i);
                p1:=p2+1;
                p2:=p3;
        until p1>p2;
end.

不懂的可以面谈或者发表评论。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值