No.661 ハローキティはりんご3個分

はじめに

競技プログラミングyukicoder
No.661 ハローキティはりんご3個分
言語はC#
何かあればTwitter→@pirorirori_n712まで

問題

入力:Nxの数+Nx(りんご1つ分を1とする)を数分
   Nxは3nまたは8nまたは10n(1≤Nx≤1000000 )の数字
出力:与えられたNxがキティ(りんご3つ分を1とする)いくつ分の重さであるか
   ただし、8の倍数である場合は、「iki」
   10の倍数である場合は「sugi」、
   8の倍数かつ10の倍数である場合には「ikisugi」
   を出力する

解き方

文章から、入力の数字Nxによって出力させるものを分けていけばいいことが分かる。

①if文で場合分けをする1(40で割る、8・10で割る、3で割る)

②if分で場合分けをする2(8で割る、10で割る、3で割る)

③その他の解き方(他の方の解答もあるのでメモ程度)

①if文で場合分けをする1

問題の定義から、数字の出力よりも文字の出力を優先させる。
つまり、優先順位は以下のようになる。
①「ikisugi」8の倍数かつ10の倍数である場合
②「iki」8の倍数である場合、「sugi」10の倍数である場合
③Nxがキティいくつ分の重さであるかの値

①について

8の倍数かつ10の倍数である場合なので、
当てはまるNxは8と10の最小公倍数の倍数であることが分かる。
すなわち、Nxを8と10の最小公倍数である40で割って、あまりがでないものが①に当てはまる。
または、8と10それぞれで割って
どちらでもあまりが出ないという解き方もできる(→Nx%8==0&&Nx%10==0)

②について

Nxが8の倍数であれば「iki」、Nxが10の倍数であれば「sugi」なので
Nxを8、或いは10で割ってあまりが出なければここの出力となる。
なお、8の倍数と10の倍数は同率の優先度となっているが
先に①で8の倍数かつ10の倍数を出しているので
この時点で、8と10どちらの倍数にもなり得る値は流れてこない。
そのため、どちらから割っても問題はない。

③について

Nx(りんご1つを1とする)をキティ(リンゴ3つを1とする)という単位に
直した際にいくつになるかを数値で出力する。
1キティはリンゴ3つ分、すなわち
Nxが3のとき1キティとなる。
与えられたNxが何キティになるのかはNxを3で割れば分かる。
なお、問題文からNxは3nまたは8nまたは10nということが確定しているので
③に流れてくる数字は全て3の倍数であり、3で割り切れる数である。

以上をもとにコードを書いていく。

コード例

using System;

class No661{
    static void Main(string[] args){
        //入力の文字を保存
        var s=Console.ReadLine();
        //string型の入力をint型に変換
        var num=Int32.Parse(s);
        //numが0以上である限りループを回す、
        //ループの最後で1ずつnumをマイナスしているのでnum回(与えられたNxの回数分)回ります
        //for(int i=0;i<num;++i)でも同じことができます
        while(num>0){
            //入力されたNxをint型に変換して変数weightに保存
            var weight=Int32.Parse(Console.ReadLine());
            //もしweightが40で割り切れたら
            if(weight%40==0){
                //「ikisugi」を出力
                Console.WriteLine("ikisugi");
            }
            //もしweightが10で割り切れたら
            else if(weight%10==0){
                //「sugi」を出力
                Console.WriteLine("sugi");
            }
            //もしweightが8で割り切れたら
            else if(weight%8==0){
                //「iki」を出力
                Console.WriteLine("iki");
            }
            //上のどれにも当てはまらない、
            //すなわち8或いは10の倍数ではないもの3n
            else{
                //weightを3で割ってキティ単位での値を出す
                weight=weight/3;
                //キティ単位の値を出力
                Console.WriteLine(weight);
            }
            //ループの最後にnumから1を引く
            num--;
        }
    }
}

少し整理して

using System;

class No661{
    static void Main(string[] args){
        //string型の入力をint型に変換して変数numに保存
        var num=Int32.Parse(Console.ReadLine());
        //numが0以上である限りループを回す、
        //ループの最後で1ずつnumをマイナスしているのでnum回(与えられたNxの回数分)回ります
        //for(int i=0;i<num;++i)でも同じことができます
        while(num>0){
            //入力されたNxをint型に変換して変数weightに保存
            var weight=Int32.Parse(Console.ReadLine());
            //もしweightが40で割り切れたら
            if(weight%40==0){
                //「ikisugi」を出力
                Console.WriteLine("ikisugi");
            }
            //もしweightが10で割り切れたら
            else if(weight%10==0){
                //「sugi」を出力
                Console.WriteLine("sugi");
            }
            //もしweightが8で割り切れたら
            else if(weight%8==0){
                //「iki」を出力
                Console.WriteLine("iki");
            }
            //上のどれにも当てはまらない、
            //すなわち8或いは10の倍数ではないもの3n
            else{
                //weightを3で割ってキティ単位での値を出力
                Console.WriteLine(weight/3);
            }
            //ループの最後にnumから1を引く
            num--;
        }
    }
}

②if分で場合分けをする2

①の変形バージョン
改行なしのConsole.WriteLine()を使って解く。
Nxが8と10で割り切れた場合の出力は「ikisugi」、
8で割り切れた場合の出力は「iki」
10で割り切れた場合の出力は「sugi」
そのため、8で割り切れ、かつ10で割り切れる場合は「iki」と「sugi」を改行なしで
出力することによって「ikisugi」を出力することができる。

場合分けは上から順に以下のようになる。
①8で割り切れる場合
→ここで改行なしの「iki」を出力
②10で割り切れる場合
→ここで「sugi」を出力する
③8でも10でも割り切れないNx(3n)を3で割る

コード例

using System;

class No661{
    static void Main(string[] args){
        //string型の入力をint型に変換して変数numに保存
        var num=Int32.Parse(Console.ReadLine());
        //numが0以上である限りループを回す、
        //ループの最後で1ずつnumをマイナスしているのでnum回(与えられたNxの回数分)回ります
        //for(int i=0;i<num;++i)でも同じことができます
        while(num>0){
            //最後の3nしか入らない部分に、3n以外のものが入らないようにフラグを設定
            //8或いは10の倍数だったらフラグをtrueにしておく
            var flg=false;
            //入力されたNxをint型に変換して変数weightに保存
            var weight=Int32.Parse(Console.ReadLine());
            //もしweightが8で割り切れたら
            if(weight%8==0){
                //「iki」を出力
                Console.Write("iki");
                flg=true;
            }
            //もしweightが10で割り切れたら
            if(weight%10==0){
                //「sugi」を出力
                Console.Write("sugi");
                flg=true;
            }
            //上のどれにも当てはまらない、
            //すなわち8或いは10の倍数ではないもの3n
            //フラグがfalseのままなら8の倍数でも10の倍数でもない3nであると言える
            if(!flg){
                //weightを3で割ってキティ単位での値を出力
                Console.Write(weight/3);
            }
            //改行をする
            Console.WriteLine();
            //ループの最後にnumから1を引く
            num--;
        }
    }
}

③その他の解き方

他の方の解答を見て知ったので
詳しい解説は避けますが
上にあげた12の方法以外にも
先に8と10で割ってしまい、結果をbool型の変数に保存
その結果で出力を決めるという方法もありました。
またif分は、条件演算子にすると場合分けを一行で行うことができます。