Copyright (C) IOI日本委員会 1995. All rights reserved.


問題4.

 n (≧2) 個のランプが円状に並んでおり、最初は、すべてのランプが点灯している。 このとき、あるひとつのランプから時計まわりに次々に以下の1 または2の操作 を行い、ランプを点灯させたり、消したりしていく。

(1)ひとつ手前のランプが点灯しているときは、 今見ているランプの状態を入れ替え (つまり、点灯していれば消し、消えていれば点灯する)、次のランプに移る。
(2)ひとつ手前のランプが点灯していないときは、 今見ているランプの状態を変えずに次のランプに移る。

 このような操作を何回か行うと、必ず、再びすべてのランプが点灯することが 知られている。 下記の3つの異なる言語で書かれたプログラムは、 キーボードからランプの個数を入力し、全てのランプが再び点灯するまでに 何回操作を行うかを出力する。ただし、 ランプの個数 n によっては操作回数はきわめて大きくなるが、 n の値のチェックや操作回数を表す変数のオ−バ−フロ−チェックは行わない。 いずれか一つの言語について、空欄の部分を埋めよ。[2点]


QuickBASICプログラム(4)

DECLARE SUB makeLinkedLamp(numLamp)
DECLARE FUNCTION countOp(numLamp)
CONST maxLamp = 1000       ' lamp の個数の最大値
TYPE lampType 
    lampState AS INTEGER   ' lampState=1/0 <==> ランプがON/OFF
    nextPtr AS INTEGER     ' 次のランプを指すポインタ 
END TYPE        
DIM SHARED linkedLamp(maxLamp) AS lampType
 
   PRINT "ランプの個数を入力してください:"
   INPUT numLamp
   PRINT "操作の回数 : "; countOp(numLamp)
END

'  サブルーチン makeLinkedLamp は、ランプの個数 numLamp を受取り、
'  linkedLamp を円状にnumLamp個のランプが並んでいるように初期化する
SUB makeLinkedLamp(numLamp)
    head = 0
    current = head
    FOR count = 1 TO numLamp-1 
        new = current + 1
        linkedLamp(current).lampState = 1
         ---------------------------------
        |            (a)                  |
         ---------------------------------
        current = new
    NEXT count     
    linkedLamp(current).lampState = 1 
    linkedLamp(current).nextPtr = head
END SUB

'  関数 countOp は、ランプの個数 numLamp を受取り、
'  再び、全てのランプが点灯するまでの操作の回数を返す 
FUNCTION countOp(numLamp)
    makeLinkedLamp(numLamp) 
    timesOp = 0             ' timesOp は操作の回数 
    numOn = numLamp         ' numOn は ON になっているランプの個数
    previous = 0
    DO
        current = linkedLamp(previous).nextPtr
            ----------------------------
        IF |         (b)                | = 1 THEN
            ----------------------------
                ----------------------------
            IF |         (c)                | = 0 THEN
                ----------------------------
                linkedLamp(current).lampState = 1 
                numOn = numOn+1 
            ELSE 
                linkedLamp(current).lampState = 0 
                numOn = numOn-1 
            END IF
        END IF
        timesOp = timesOp+1 
        previous = current 
    LOOP UNTIL numOn = numLamp 
    countOp = timesOp
END SUB    


Cプログラム(4)

#include <stdio.h>
#include <stdlib.h>

#define ON  1
#define OFF 0

typedef struct linked_lamp {
    int lamp_state;                 /* ランプの ON/OFF 状態 */
    struct linked_lamp *next_ptr;   /* 次のランプを指すポインタ */
} lamp_type;

lamp_type *lamp_alloc(void);
lamp_type *make_linked_lamp(int);
long int count_op(int);

void main() 
{
    int num_lamp;                   /* ランプの個数 */

    printf("ランプの個数を入力してください: ");
    scanf("%d", &num_lamp);

    printf("操作の回数 : %ld\n", count_op(num_lamp));
}

/*  関数 lamp_alloc は新しいランプのための領域を確保しそのアドレスを返す */
lamp_type *lamp_alloc(void) 
{
    return (lamp_type *)malloc(sizeof(lamp_type));
}

/*  関数 make_linked_lamp は、ランプの個数 num_lamp を受取り、 */
/*  円状にnum_lamp個のランプを並べ、あるひとつのランプへのポインタを返す */
lamp_type *make_linked_lamp(int num_lamp) 
{
    int count;
    lamp_type *head, *current, *next;
    
    head = lamp_alloc();
    for (count=0, current=head; count < num_lamp-1; count++) {
        next = lamp_alloc();        
        current->lamp_state = 1; 
         ------------------------
        |        (a)             |
         ------------------------
        current = next;
    }
    current->lamp_state = ON; 
    current->next_ptr = head;
    return head;
}

/*  関数 count_op は、ランプの個数 num_lamp を受取り、*/
/*  再び、全てのランプが点灯するまでの操作の回数を返す */
long int count_op(int num_lamp)
{
    int num_on;              /* ON になっているランプの個数 */
    long int times_op;       /* 操作の回数 */
    lamp_type *current,      /* 現在見ているランプ */
              *previous;     /* ひとつ手前のランプ */

    times_op = 0;
    num_on = num_lamp;
    previous = make_linked_lamp(num_lamp);
    do {
        current = previous->next_ptr;
             ------------------
        if (|     (b)          |==ON)
             ------------------
                 ------------------
            if (|     (c)          |==OFF)
                 ------------------
                current->lamp_state = ON; 
                num_on++; 
            } 
            else { 
                current->lamp_state = OFF; 
                num_on--; 
            };  
        times_op++; 
        previous = current; 
    } while (num_on!=num_lamp);
    return times_op;
}


Pascalプログラム(4)

program problem4;
    const on = 1; off =0;
    type lamp_type = ^linked_lamp; 
         linked_lamp = record                
             lamp_state: integer; { ランプの ON/OFF 状態 } 
             next_ptr: lamp_type  { 次のランプを指すポインタ }
         end;

    { 関数 make_linked_lamp は、ランプの個数 num_lamp を受取り、
      円状にnum_lamp個のランプを並べ、あるひとつのランプへのポインタを返す }
    function make_linked_lamp(num_lamp: integer): lamp_type;
        var count: integer;
            head,current,next: lamp_type;
    begin
        new(head);
        current := head;
        for count:=1 to num_lamp-1 do begin
            new(next);
            current^.lamp_state := on; 
             --------------------------
            |          (a)             |
             --------------------------
            current := next;  
        end;
        current^.lamp_state := on; 
        current^.next_ptr := head;
        make_linked_lamp := head;
    end;

    { 関数 count_op は、ランプの個数 num_lamp を受取り、
      再び、全てのランプが点灯するまでの操作の回数を返す }
    function count_op(num_lamp: integer): longint;
        var num_on: integer;      { ON になっているランプの個数 } 
            times_op: longint;    { 操作の回数 }
            current:  lamp_type;  { 現在見ているランプ }
            previous: lamp_type;  { ひとつ手前のランプ }
    begin
        times_op := 0; 
        num_on := num_lamp;   
        previous := make_linked_lamp(num_lamp);
        repeat
            current := previous^.next_ptr;
                -------------------
            if |       (b)         | = on then
                -------------------
                    -------------------
                if |       (c)         | = off then
                    -------------------
                    current^.lamp_state := on; 
                    num_on := num_on+1 
                end
                else begin
                    current^.lamp_state := off; 
                    num_on := num_on-1 
                end;
            times_op := times_op+1; 
            previous := current 
        until num_on = num_lamp ;
        count_op := times_op;
    end;

    var num_lamp : integer;       { ランプの個数 }

begin 
    write('ランプの個数を入力してください: '); 
    readln(num_lamp);
    writeln('操作の回数 : ', count_op(num_lamp));
end.


JOI'95へ戻る

JOIホームページへ戻る