[1_4_clocks] constant time solution

来源:互联网 发布:linux查看目录大小命令 编辑:程序博客网 时间:2024/05/17 13:09
The Clocks
IOI'94 - Day 2
Consider nine clocks arranged in a 3x3 array thusly:
|-------|    |-------|    |-------|    |       |    |       |    |   |   |    |---O   |    |---O   |    |   O   |          |       |    |       |    |       |           |-------|    |-------|    |-------|        A            B            C|-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O   |    |   O   ||   |   |    |   |   |    |   |   ||-------|    |-------|    |-------|    D            E            F|-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O---|    |   O   ||   |   |    |       |    |   |   ||-------|    |-------|    |-------|    G            H            I

The goal is to find a minimal sequence of moves to return all the dials to 12 o'clock. Nine different ways to turn the dials on the clocks are supplied via a table below; each way is called a move. Select for each move a number 1 through 9 which will cause the dials of the affected clocks (see next table) to be turned 90 degrees clockwise.MoveAffected clocks1ABDE2ABC3BCEF4ADG5BDEFH6CFI7DEGH8GHI9EFHI

Example

Each number represents a time accoring to following table:
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 

[But this might or might not be the `correct' answer; see below.]

PROGRAM NAME: clocks

INPUT FORMAT

Lines 1-3:Three lines of three space-separated numbers; each number represents the start time of one clock, 3, 6, 9, or 12. The ordering of the numbers corresponds to the first example above.

SAMPLE INPUT (file clocks.in)

9 9 126 6 66 3 6

OUTPUT FORMAT

A single line that contains a space separated list of the shortest sequence of moves (designated by numbers) which returns all the clocks to 12:00. If there is more than one solution, print the one which gives the lowest number when the moves are concatenated (e.g., 5 2 4 6 < 9 3 1 1).

SAMPLE OUTPUT (file clocks.out)

4 5 8 9





Notice that the order in which we apply moves is irrelevant, and that applying a move four times is the same as applying it not at all.

Thus there are only 49 = 262144 move sequences that need to be tried, so we might as well just try them all.

We don't generate them shortest first, but looking at sequences of the same length, we generate the lesser ones before the greater ones, so we only need to keep track of the shortest working sequence we've found.

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <ctype.h>#define INF 60000/* bigger than longest possible path */char *movestr[] = { "abde", "abc", "bcef", "adg", "bdefh", "cfi", "degh",                    "ghi", "efhi" };int movedist[9][9];int clock[9];int bestmove[9];int nbestmove;/* translate move strings into array "movedist" of which clocks change on each move */voidmkmove(void){    int i;    char *p;    for(i=0; i<9; i++)for(p=movestr[i]; *p; p++)    movedist[i][*p-'a'] = 3;}/* apply some number of each move from k to 9 *//* move contains the number of times each move is applied */voidsolve(int *move, int k){    int i, j, n, rep;    if(k == 9) {for(j=0; j<9; j++)    if(clock[j]%12 != 0)return;/* we have a successful sequence of moves */n = 0;for(j=0; j<9; j++)    n += move[j];if(nbestmove == 0 || n < nbestmove) {    nbestmove = n;    for(j=0; j<9; j++)bestmove[j] = move[j];}return;    }    /*     * the for loop counts down so we     * generate smaller numbers first by     * trying more of small numbered     * moves before we try less of them.     */    for(rep=3; rep>=0; rep--) {/* apply move k rep times */for(i=0; i<rep; i++)    for(j=0; j<9; j++)clock[j] += movedist[k][j];move[k] = rep;solve(move, k+1);/* undo move */for(i=0; i<rep; i++)    for(j=0; j<9; j++)clock[j] -= movedist[k][j];    }}voidmain(void){    FILE *fin, *fout;    int i, j, move[9];    char *sep;    fin = fopen("clocks.in", "r");    fout = fopen("clocks.out", "w");    assert(fin != NULL && fout != NULL);    mkmove();    for(i=0; i<9; i++)fscanf(fin, "%d", &clock[i]);    solve(move, 0);    sep = "";    for(i=0; i<9; i++) {for(j=0; j<bestmove[i]; j++) {    fprintf(fout, "%s%d", sep, i+1);    sep = " ";}    }    fprintf(fout, "\n");    exit(0);}

Lucian Boca submitted a constant time solution

You can precalculate a matrix a as following:

a[i][0],a[i][1],....,a[i][8] is the number of moves '1','2','3',...'9' necessarly to move ONLY clock i (where 0 < i <= 8 - there are 9 clocks: 0=A, 1=B, ... 8=I) 90 degrees clockwise. So, you have the matrix:

int a[9][9]= { {3,3,3,3,3,2,3,2,0},               {2,3,2,3,2,3,1,0,1},               {3,3,3,2,3,3,0,2,3},               {2,3,1,3,2,0,2,3,1},               {2,3,2,3,1,3,2,3,2},               {1,3,2,0,2,3,1,3,2},               {3,2,0,3,3,2,3,3,3},               {1,0,1,3,2,3,2,3,2},               {0,2,3,2,3,3,3,3,3} };

That means: to move ONLY the clock 0 (clock A) 90 degrees clockwise you have to do {3,3,3,3,3,2,3,2,0}, 3 moves of type 1, three moves of type 2, ..., 2 moves of type 8, 0 moves of type 9, etc.

To move ONLY the clock 8 (clock I), you have to do the moves {0,2,3,2,3,3,3,3,3}: 0 moves of type 1, 2 moves of type 2... 3 moves of type 9....

That's it! You count in a vector v[9] how many moves of each type you have to do, and the results will be modulo 4 (%4 - 5 moves of any type have the same effect 1 move has). The source code:

#include <stdio.h>int a[9][9]= { {3,3,3,3,3,2,3,2,0},               {2,3,2,3,2,3,1,0,1},               {3,3,3,2,3,3,0,2,3},               {2,3,1,3,2,0,2,3,1},               {2,3,2,3,1,3,2,3,2},               {1,3,2,0,2,3,1,3,2},               {3,2,0,3,3,2,3,3,3},               {1,0,1,3,2,3,2,3,2},               {0,2,3,2,3,3,3,3,3} };int v[9];int main() {    int i,j,k;    freopen("clocks.in","r",stdin);    for (i=0; i<9; i++) {        scanf("%d",&k);        for(j=0; j<9; j++)             v[j]=(v[j]+(4-k/3)*a[i][j])%4;    }    fclose(stdin);    k=0;    freopen("clocks.out","w",stdout);    for (i=0; i<9; i++)        for (j=0; j<v[i]; j++)            if (!k) { printf("%d",i+1); k=1; }            else    printf(" %d",i+1);    printf("\n");    fclose(stdout);    return 0;}

Here's a different approach from Sopot Cela -- no loops, constant time. It is, however, extraordinarily intricate: getting such a program correct in a contest environment could be extremely challenging:

program clocks;const  INV : array[3..12] of byte =(1, 0, 0, 2, 0, 0, 3, 0, 0, 0);var inp, out: text;    a, b, c, d, e, f, g, h, i: integer;    ax, bx, cx, dx, ex, fx, gx, hx, ix,l: integer;    t,an: array[1..9] of integer;begin    assign (inp, 'clocks.in'); reset (inp);    readln(inp, ax, bx, cx);    readln(inp, dx, ex, fx);    readln(inp, gx, hx, ix);    a:=inv[ax]; b:=inv[bx]; c:=inv[cx]; d:=inv[dx];    e:=inv[ex]; f:=inv[fx]; g:=inv[gx]; h:=inv[hx];    i:=inv[ix];    t[1] := (8+a+2*b+c+2*d+2*e-f+g-h) mod 4;    t[2] := (a+b+c+d+e+f+2*g+    2*i) mod 4;    t[3] := (8+  a+2*b+  c  -d+2*e+2*f      -h+  i) mod 4;    t[4] := (    a+  b+2*c+  d+  e+      g+  h+2*i) mod 4;    t[5] := (4+  a+2*b+  c+2*d  -e+2*f+  g+2*h+  i) mod 4;    t[6] := (  2*a+  b+  c+      e+  f+2*g+  h+  i) mod 4;    t[7] := (8+  a  -b+    2*d+2*e  -f+  g+2*h+  i) mod 4;    t[8] := (  2*a+    2*c+  d+  e+  f+  g+  h+  i) mod 4;    t[9] := (8      -b+  c  -d+2*e+2*f+  g+2*h+  i) mod 4;    assign(out, 'clocks.out'); rewrite(out);    for a := 1 to 9 dofor b := 1 to t[a] do Begin    inc(l);    an[l]:=a;end;    for a:=1 to l-1 dowrite(out,an[a],' ');    write(out,an[l]);    writeln(out); close(out)end.




原创粉丝点击