【USACO题库】1.4.2 The Clocks

本文介绍了一个经典的广度优先搜索算法案例——3x3时钟谜题。通过定义九个时钟及其旋转操作,寻找最少步骤使所有时钟指针指向12点的方法。使用Pascal语言实现,详细解释了状态表示和搜索过程。
题目描述
考虑将如此安排在一个 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

总结:

这就是一道非常非常典型的广搜题,我们只需要用一个九维数组来模拟bz,但是不要用3..12,要压缩成1..4

代码:(pascal)

const
        data:array[1..9,0..5]of longint=((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));
var
        i,j,n,m,head,tail,k,l:longint;
        a:array[0..300000,0..10]of longint;
        bz:array[1..4,1..4,1..4,1..4,1..4,1..4,1..4,1..4,1..4] of boolean;
        map:array[1..9]of longint;
function pd(t:longint):boolean;
var
        i:longint;
begin
        for i:=1 to 9 do
                if a[t,i]<>4 then exit(false);
        exit(true);
end;
procedure paint(t:longint);
begin
        if a[t,0]>1 then
                paint(a[t,0]);
        write(a[t,10],' ');
end;
begin
        for i:=1 to 9 do
        begin
                read(map[i]);
                map[i]:=map[i] div 3;
        end;
        head:=0;
        tail:=1;
        for i:=1 to 9 do
                a[1,i]:=map[i];
        bz[map[1],map[2],map[3],map[4],map[5],map[6],map[7],map[8],map[9]]:=true;
        repeat
                inc(head);
                for i:=1 to 9 do
                begin
                        inc(tail);
                        a[tail]:=a[head];
                        a[tail,0]:=head;
                        a[tail,10]:=i;
                        for j:=1 to data[i,0] do
                        begin
                                inc(a[tail,data[i,j]]);
                                if a[tail,data[i,j]]>4 then a[tail,data[i,j]]:=1;
                        end;
                        if bz[a[tail,1],a[tail,2],a[tail,3],a[tail,4],a[tail,5],a[tail,6],a[tail,7],a[tail,8],a[tail,9]] then
                                dec(tail)
                        else
                        begin
                                bz[a[tail,1],a[tail,2],a[tail,3],a[tail,4],a[tail,5],a[tail,6],a[tail,7],a[tail,8],a[tail,9]]:=true;
                                if pd(tail) then
                                begin
                                        paint(tail);
                                        halt;
                                end;
                        end;
                end;
        until head>=tail;
end.


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值