分数 意地悪すごろく(旧)

ユークリッドの互除法 の 応用問題です。

【STEP: 1】コード

reader.on('close', () => {
   const [sA, sB, cal, sC, sD] = lines[0].split(' ');
   const [A, B, C, D] = [sA, sB, sC, sD].map(Number);
   let [n, d, x] = [0, 0, 1];  // n → 分子 d → 分母 xnとdの最大公約数
   switch (cal) {  // A / B cal C / D の演算
   case '+':
      d = B * D;
      n = A * D + C * B;
      break;
   case '-':
      d = B * D;
      n = A * D - C * B;
      break;
   case '*':
      d = B * D;
      n = A * C;
      break;
   case '/':
      n = A * D;
      d = B * C;
      break;
   }
   if (Math.sign(n) === -1 && Math.sign(d) === -1) {
   // n, d 双方が負の数なら -1 を乗算して符号を変換
      n = n * -1;
      d = d * -1;
   }
   gcd(Math.abs(n), Math.abs(d));  // n, d の絶対値を引数としてgcd()を呼び出し
   console.log(n / x, d / x);  // n, dx で割って 出力

   function gcd(a, b) {  // 最大公約数を求めて x の値を上書きする関数
      while (a && b) {
         if (a > b) {
            a = a % b;
         } else {
            b = b % a;
         }
      }
      a ? x = a : x = b;
   }
});
hogeちゃんの画像

分数を通分して 式の計算を行い  分子と分母の最大公約数で約分した値を出力しました。

【FINAL】コード 1

reader.on('close', () => {
   function gcd(a, b) {
      const [A, B] = [a, b];  // 元の値をコピーして保存
      if (a < b) {  // a < b なら
         [a, b] = [b, a];  // a, b の値を入れ替え
      }
     while (a && b) {  // a, b が 0 でなければ
        a %= b;  // aa % b で上書き
        [a, b] = [b, a];  // a, b の値を入れ替え
     }
     if (N % a === 0 || a > Math.min(A, B) || B === A) {
         return B;
      }
   }
   const [N, A] = lines[0].split(' ').map(Number);
   const S = new Set();  // サイコロの目
   for (let i = 1; i <= 1000; i++) {
      S.add(i);  // 1〜1000の値(サイコロの目)を S に保存
   }
   for (let i = 1; i <= 1000; i++) {
      const B = i;
      S.delete(gcd(A, B));  // S から gcd() の戻り値を削除
   }
   if (S.size) {  // S に値があれば
      S.forEach(s => {
         console.log(s);  // S の各要素を表示
      });
   } else {  // さもなくば
      console.log(-1);  // -1 を表示
   }
});
hogeちゃんの画像

NAi の 最大公約数 で割り切れない時は ゴールできないので 1 〜 1000 を S に保存してから gcd(A, B) を実行して戻り値を削除しました。

【FINAL】コード 2《C++の実装例参照》

reader.on('close', () => {
   function gcd(a, b) {
      if (b === 0) {
         return a;
      }
      return gcd(b, a % b);
   }
   const [N, A] = lines[0].split(' ').map(Number);
   let none = true;
   for (let i = 1; i <= 1000; i++) {
      min_move = gcd(A, i);
      if (N % min_move !== 0 && i !== A) {
         console.log(i);
         none = false;
      }
   }
   if (none) {
      console.log(-1);
   }
});
hogeちゃんの画像

解答コード例・C++の場合を 書き換えるとこんな感じ…。function gcd(a, b)の内部で gcd(a, a % b) 呼び出して return すれば 処理をループさせることができるみたい。

コメント