プログラム言語C1 平成19, 20年度 中間および期末解答 과제空間



平成19年度昼間コースプログラミング言語I中間試験解答例
(あくまでも解答例です)

問1.
(1) x個書いたら次の行に移るので、行はyをxで割った商で求めることが
    できる。ただし、単純に割ると0行目から始まることになってしまう
    ので、求めた商に1を足すようにする。
    列は1行に満たない分ということだから、yをxで割った余りで求める
    ことができる。これも行と同様単純に余りを求めると0列目から始ま
    るので、求めた余りに1を足すようにする。

        (a) y / x + 1
        (b) y % x + 1

(2) 行については変更する必要はないので、列のみ考える。(1)だと左か
    らの位置になるので、偶数行のときは右からの位置になるようにす
    ればよい。通常の1列目はx列目に、2列目はx-1列目になるというこ
    とだから、n列目はx-n+1列目になるということである。通常のn列目
    は上記の(b)で求められるからnの部分に(b)を入れるとx-y%xとなる。
    あとはこれを偶数行のとき、つまり (y/x+1)%2が0のときに求める
    ようにすればよい。

        8行目を次のように変更する。

        if ((v % 2 == 0)
           w = x - y % x;
        else
           w = y % x + 1;


問2.
(1) 動きを追っていけばよい。

      (a) 21        (b) 233

(2) for文とwhile文の意味を考えて変換すればよい。

      i = 2;
      while (i <= n) {
        a3 = a1 + a2;
        a1 = a2;
        a2 = a3;
        i++;
      }

(3) for文のループの条件式が省略されている場合は常に条件が成り立って
    いるということになり、このままでは無限ループになる。ループの途中
    でループから抜けるには、breakを用いればよい。抜けるタイミングは、
    変数iがnを超えたときであるから、i>nを条件とするif文にすればよい。

      10行目と11行目の間に以下の文を入れる。

      if (i > n) break;


問3.
(1) switch文におけるbreakの役割がポイントである。

    (a)入力値が1,9,11のときに本来は2と出力されるべきところが、1と
       出力されてしまう。
    (b)これは、9行目の最後にbreak;がないため、次の10行目にある。h=1;
       が実行されてしまうからである。
    (c)9行目の最後にbreak;を付ければよい。

(2) switch文の動きは条件式の値がどの値と一致するかで分岐を制御する。
    if文で記述するには、値の一致を調べる"=="の演算子で条件式を記述
    すればよい。

      if (m == 5) h = 3;
      else if (m == 1 || m == 9 || m == 11) h = 2;
      else if (m == 2 || m == 3 || m == 4 || m = 7 || m == 10 || m == 12)
        h = 1;
      else if (m == 6 || m == 8) h = 0;

   
問4.
(1) 何列目を出力しているかを表す変数はjなので、この値が奇数か偶数
    かで"#"を出力するか"@"を出力するかを変えてあげればよい。

      9行目を次のように変更する

      if (j % 2 == 0) printf("#");
      else printf("@");

(2) まず、for文を見ると行と列は0から始まっている。このとき、偶数行
    の偶数列、奇数行の奇数列のときは"#"が出力され、偶数行の奇数列、
    奇数行の偶数列のときは"@"が出力されていることが分かる。これを
    単純に条件にすると、

      if ((i % 2 == 0 && j % 2 == 0) || (i % 2 == 1 && j % 2 == 1))
        printf("#");
      else if ((i % 2 == 0 && j % 2 == 1) || (i % 2 == 1 && j % 2 == 0))
        printf("@");

    となる。これを9行目に変更すればよい。

    ただ、よく条件を見ると、"#"は行と列を足した値が偶数、"@"は行
    と列を足した値が奇数になるということであることが分かる。これ
    より、

      if ((i + j) % 2 == 0) printf("#");
      else printf("@");

    としてもよい。

(3) 左上から右下への対角線は、行と列が同じ値の部分のつながりである。
    つまり行をi、列をjとすると"i == j"のときに"@"を出力させればよい。
    右上から左下への対角線は、入力値が6のときの例を見ると0行目は5列
    目、1行目は4列目、...、5行目は0列目に"@"が出力されている。つまり
    入力nの場合は0行目はn-1列目、1行目はn-2列目の部分に"@"を出力して
    いくことになるので、i行目はn-1-i列目の部分に"@"を出力させればよい。
    この条件式は"(j == n-1-i)"に書ける。これらの2つの条件のどちらかが
    成り立ったときに"@"を出力するようにすれば、対角線の部分が"@"に
    なる。

      9行目を次のように変更する
     
      if ((i == j) || (j == n - 1 - i)) printf("@");
      else printf("#");


==============================================================================================

平成19年度昼間コースプログラミング言語I期末試験解答例
(あくまでも解答例です)

問1.
(1) 式のとおりの計算を行うように記述すればよい。ただし、割り算には注意。

      w = (a + b + c) / 2.0;
      area = sqrt(w * (w - a) * (w - b) * (w - c));

(2) 二等辺三角形である条件は2つの辺の長さが同じかどうかである。
    入力値は小さい順に並んでいるから、aとbまたはbとcが同じであるか
    調べればよい。

      if (a == b || b == c)
        printf("二等辺三角形です\n");

(3) ループの条件として、各辺に0以下の値があるか(a <= 0 || b <= 0 || c <= 0)
    1番長い辺が残りの2つの和以上である(c >= a + b)ようにすればよい。

      do {
        scanf("%d %d %d", &a, &b, &c);
      } while (a <= 0 || b <= 0 || c <= 0 || c >= a + b);


問2.
(1) 再帰に気を付けながらプログラムの動きを追えばよい。

       (a) 30
       (b) 317

(2) 入力値(n)が正か負かで処理を切り替えればよい。

      13行目を以下のように変更する。

      if (n > 0)
        printf("%d\n", func(n, 1));
      else
        printf("%d\n", -func(-n, 1));


問3.
(1) 正しくURLが入力されたとすると、str[7]からサーバ名が始まることに
    なる。ここから'/'まで、あるいは文字列の最後まで取り出せばよいので、
    ループの条件はstr[i]が'/'ではない、かつ'\0'ではない、となる。

      (a) str[i + 7] != '/' && str[i + 7] != '\0'
      (b) str[i + 7]

(2) 8〜9行目のループでサーバ名を配列strに入れていくが、このとき変数i
    は配列serverのどの部分に文字を入れるかを表している。これがサーバ名
    の最後の文字まで繰り返され、最後に10行目でstr[i]の位置に'\0'を入れ
    ている。つまり、最後の文字はi-1の場所であり、そこから2つ前までを
    調べればよい。

      if (server[i-3] == '.' && server[i-2] == 'j' && server[i-1] == 'p')
        printf("日本のドメインです\n");

(3) 方法はいろいろ考えられるが、入力が正しく"http://"または"ftp://"で
    始まるとするなら、str[6]の文字が'/'であるかどうかで切り替えるのが
    簡単である。

      6行目: int型変数pを追加
      7行目と8行目の間: if (str[6] == '/') p = 7; else p = 6;
      8行目: for (i = 0; str[i + p] != '/' && str[i + p] != '\0' ; i++)
      9行目: server[i] = str[i + p];

  
問4.
(1) for文の2重ループで記述すればよい。

      for (x = 0; x < 3; x++)
        for (y = 0; y < 3; y++)
          borad[x][y] = 0;

(2) ○のときには縦横斜めのそれぞれを足した値が3に、×のときには-3に
    なっているとき、つまり引数の3倍になっているときに1を返せばよい。

      int win(int n)
      {
        int i;
        for (i = 0; i < 3; i++) {
          if (board[i][0] + board[i][1] + board[i][2] == n * 3)
            return 1;
          if (board[0][i] + board[1][i] + board[2][i] == n * 3)
            return 1;
        }
    if (board[0][0] + board[1][1] + board[2][2] == n * 3)
          return 1;
    if (board[0][2] + board[1][1] + board[2][0] == n * 3)
          return 1;
        return 0;
      }


=================================================================================================


平成20年度昼間コースプログラミング言語I中間試験解答例
(あくまでも解答例です)

問1.
(1) 入力値mについて100が何個分あるかを調べるには、mを100で割った
    商を求めればよい。次に50が何個分あるかを調べるが、ここで注意
    すべき点は、入力値から100の分を除いた値を用いて調べないといけ
    ない点である。最後に、入力値から100の分と50の分を除いた値で
    10の分を求めればよい。

      (a) m / 100
      (b) (m - a * 100) / 50   または   (m % 100) / 50
      (c) (m - a * 100 - b * 50) / 10 または ((m % 100) % 50) / 10
          または (m % 50) / 10   <-- 100 は 50 で割り切れるので

(2) 1の位がある場合、10円分多く支払う必要がある。1の位があるか
    どうかは入力値を10で割ったときに余りが出るかどうかで判断できる。
    つまり、余りが0でないときには入力値の1の位を切り上げればよい。
    切り上げの方法はいろいろ考えられるが、10で割った余りを10から
    引いた分を入力値に足してあげてもよい。

      6行目と7行目の間に以下を加える。

        if (m % 10 != 0)
           m += (10 - (m % 10));

        あるいは

        if (m % 10 != 0)
           m = (m / 10) * 10 + 10;
        /* 10で割った商に10を掛ければ1の位がなくなり、それに10を足す */

      条件分岐にする必要ないと思う人がいるかもしれないが、もし

        m += (10 - (m % 10));

      だけだと、1の位が0のときにおかしくなるので注意(例えば、580が
      入力されたときには足す必要がないのに10を足してしまう)。

    a,b,c,を計算した後に1の位の処理を行ってもよいが、面倒くさくなる。
    例えば、545が入力されたときには100円5枚、10円4枚で、1の位が
    あるで10円を1枚追加すればよいが、そうすると 10円5枚になるので
    50円1枚の方が枚数が少なくなる。つまり、追加した後に10円が5枚に
    なったら10円を0枚にして50円を1枚追加するように変更しなければ
    ならない。また、その変更でさらに50円が2枚になったら50円を0枚に
    して100円を1枚追加するようにしないといけない。


問2.
(1) nが0以下になるまで、nを10で割った余りにgを掛けた値をrに加えて
    いけばよい。ただし、繰り返しのたびにnは1/10になり、gは倍に
    なっていく。

      (a) 5        (b) 23

    ちなみに、このプログラムは2進数を10進数に変換するプログラムである。

(2) while文とfor文の記述に基づいて変換すればよい。

      for ( ;n > 0; ) {
        r += g * (n % 10);
        n /= 10;
        g *= 2;
      }


問3.
(1) nはswitch文の条件式として使われているので、この値で動作を
    切り替えていることになる。switch文を見ると、点数の2桁目以上
    の値で動作を切り替えているのが分かるので、入力値を10で割った
    商をnにしてあげればよいことになる。

      m / 10

(2) 12行目の最後に break; がないので、C判定の場合でもD判定になって
    しまう。これは 12行目の最後に break; を入れてあげればよい。

    15行目の出力で、変数rはchar型であるが書式に整数を出力する"%d"を
    使ってしまっているので正しい出力が行われない。これは"%c"に変更
    すればよい。

(3) switch文の動きは条件式の値がどの値と一致するかで分岐を制御する。
    if文で記述するには、値の一致を調べる"=="の演算子で条件式を記述
    すればよい。

      if (n == 8 || n == 9 || n == 10) r = 'A';
      else if (n == 7) r = 'B';
      else if (n == 6) r = 'C';
      else r = 'D';

   
問4.
(1) 変数iとjの値はそれぞれ金貨と銀貨の枚数を表している。これらの
    値を変化させて、重さの制約をクリアしていればそのパターンを出力
    するようになっているので、(a)には現在のパターンの場合の重さを
    計算する式が、(b)にはそのパターンのときの価値の合計を計算する
    式を入れればよい。

      (a) i * GCW + j * SCW

      (b) i * GCV + j * SCV

(2) iとjがともに0のときには何も出力されないようにすればよい。
    continue を使ってもよいが、14行目の出力をiとjがともに0で
    あるということはない、つまりどちらかが0以外であるときに
    出力させるようにすればよい。

      14行目を次のように変更する

        if (i != 0 || j != 0)
          printf("金貨%d枚、銀貨%d枚で価値の合計は%dです。\n",
                                  i, j, _____(b)_____);

(3) パターンの価値の合計は(1)(b)にある式で計算できる。可能な
    パターンのときに価値の合計が変数vより大きいときには、その
    値を変数vに入れることを行えば、ループの終了後にはvの中には
    価値の合計の最大値が入っていることになる。

      13〜14行目を以下のように変更する。
      if ( i * GCW + j * SCW <= w) {
        x = i * GCV + j * SCV;
        printf("金貨%d枚、銀貨%d枚で価値の合計は%dです。\n", i, j, x);
        if (x > v) v = x;
      }


=================================================================================================


平成20年度昼間コースプログラミング言語I期末試験解答例
(あくまでも解答例です)

問1.
(1) pはリンゴの個数だから、入力された金額を1個の値段で割った商を求めれ
    ばよい。お釣りは余りである。

      (a) n / PRICE
      (b) n % PRICE   または   n - p * PRICE  でもよい

(2) 袋が何枚必要であるかは、10個までが1枚、20個までが2枚、といったよう
    になる。ここで単純に p / 10 とすると、9個までは0になってしまうので
    ダメである。では、 p / 10 + 1 にすればよいかというと、p が 10 の
    ときに2になってしまうので、これでもダメである。どうすればよいかと
    いうと、p が 10で割り切れないときに1を加えてあがればよい。

      m = p / 10;
      if (p % 10) m++;

(3) 30個超えるかどうかは、入力された値が4,500を超えるかどうかで判断で
    きる。超えている場合、入力値から4,500を引いた分で何個買えるか計算
    すればよい。

      8行目と9行目を次のように変更
      if (n > 4500) {
        p = 30 + (n - 4500) / 120;
        r = n - 4500 - (p - 30) * 120;
      }
      else {
        p = n / PRICE;
        r = n % PRICE;
      }


問2.
(1) 2つの入力値が共に0以上の値になるまでループをさせるので、ループの条
    件は2つの入力のどちらかが0未満の値であるかどうか、ということになる。

      x < 0 || y < 0

(2) 動きを追っていけばよい。ちなみに、ここで計算しているのはアッカーマ
    ン関数と呼ばれるものである。

      (a) 2
      (b) 3


問3.
(1) 10〜11行目の部分では、文字分削除するために、i番目の部分にn個先、つ
    まりi+n番目の文字を入れ直すことを行っている。この処理は文字列の最
    後まで行えばよいことになる。文字列の長さはmに入っているから、これ
    を用いればよいが、ヌル文字まで処理しないといけないことに注意する。

      (a) i + n < m + 1
      (b) str[i] = str[i + n];

(2) 文字列の長さは m であるから、x + n - 1 が m を超えたら全部削除する
    (つまり、str[x - 1] を '\0'にする)ようにすればよい。

      10〜11行目を次のように変更
      if (x - 1 + n > m)
        str[x - 1] = '\0';
      else {
        for (i = x - 1; i + n < m + 1; i++)
          str[i] = str[i + n];
      }

  
問4.
(1) for文の2重ループで記述すればよい。どの変数が何を表しているのかを混
    同しないようにする。

      for (i = 0; i < n; i++)
        for (j = 0; j < m; j++)
          scanf("%d", &p[i][j]);

(2) 19行目を見ると平均点は a / b で計算していることが分かる。つまり、a
    には科目毎の学生の点数の合計、bにはその科目を受験した人数が入るよ
    うにすればよい。ただし、-1の場合は省く必要がある。
    また、これらの変数は、各科目を計算する毎に初期値として0にし
    ておく必要がある。

      (b) a = 0; b = 0;
      (c) if (p[j][i] != -1) {
            a += p[j][i];
            b++;
          }


덧글

  • 매모리 2009/08/04 12:50 # 답글

    시험 문제인가 보군요..
    문제보다 일본어가 어럽군요
  • 아즈마 2009/08/04 12:57 #

    작년과 제작년도 중간 기말 모범 답안이라더군요...
    하지만 구조상 제대로 돌아가게 끔만 끄적여도 되기에...
댓글 입력 영역



이글루스 8주년 기념 위젯