読者です 読者をやめる 読者になる 読者になる

CodeIQ Blog

自分の実力を知りたいITエンジニア向けの、実務スキル評価サービス「CodeIQ(コードアイキュー)」の公式ブログです。

「C/C++:ちゃんとコーディング」最高得点者発表~Ozyさんの解説付き #coding

ランキング 問題解説

CodeIQ中の人、millionsmileです。

C/C++:ちゃんとコーディング」問題の最高得点者の発表と出題者Ozyさんによる解説です。
笑いあり涙ありの解説文です。

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

はじめに

こんにちは、Ozyです。
普段は主にショートコーディングという特殊なプログラミングの遊びで出題していますが、何度か出題しているうちに思ったことが1つあります。

ちゃんと問題文読まんかい(`Д´)ノ

CodeIQの中の人に言われました。

CodeIQではできるだけポジティブな文章を書くことを推奨しています。

そうそう、わかっておりますとも。でもね、これは単なる腕試しだから良いとして、実際就職しようとしているとか、仕事でプログラム書いたりするのに、最低限きちんとしておかないといけないこともあります。だから、今回はちょっと厳しくしました。
具体的には、

余計な出力があるものはアウト

たとえば、「入力データは××です」みたいな文言が出力に含まれているもの。わかりやすく書いたのかもしれないけれども、指定と違う書式というのはダメです。

impossibleの綴りが違う!!

解けない問題の場合、"impossible"と出力するように指定しています。これが、"imposible"みたいに's'が1個足りないというような単純ミスも不正解扱いとしました。綴りに自信がなければ、問題本文からコピペしてください。

改行・空白文字
x = 2

と出力すべきところを、

x=2

と出力するとアウトです。何故かというと、問題本文に、空白を入れるように指定してあるからです。「え~、そのくらいエエやん!」と思うかもしれませんが、こういうルールも“ちゃんと”守って完璧なコードを書いた挑戦者(後述)がいるのです。


というわけで、まずはテストケースの簡単な解説をしておきます。

テストデータの解説

今回は、4つのテストケースを用意しました。

テストケース1

問題文の例と全く同じデータです。提出前にテストしていれば、これが不正解になることはないはずです。テストをする場合も、単に目視でのチェックではなくdiffコマンドを使う等、正確なチェックをしましょう。そうでしておかないと、たとえば"impossible"という単語の綴りが間違えていた場合の不正解や、書式の間違いを見逃すことになります。

テストケース2

テストケース1と大差はありませんが、符号のチェック・約分が甘いと不正解になるデータです。例のデータだけで安心せず、色々な場所に'-'を付けてみたり、乱数を使って自分で問題を作るなどして入念にチェックしておけば、このケースで不正解になることはないと思います。

テストケース3

テストケース3は、大きめの値が1000組与えられます。たとえば、

-355817016 -182909952 -64304280 -58588344

のようなもので、解は

x = -29/68

のように、約分すると分母・分子が比較的小さな値になるものです。ユークリッドの互除法を使って約分できていれば問題ないと思いますが、符号の取り扱いを適切に行わないと間違いやすいです。また、互除法を使わずに2, 3, ...と試し割していると、時間制限にかかる可能性が高くなります。注意しましょう。

テストケース4

最後のテストケースは3番目のものによく似ていますが、計算の過程で変数が符号付き32ビットを超えてしまう場合を含んだデータのセットです。
問題本文には、

約分後の分母・分子の値も符号付き32bit整数の範囲で収まる

とありますから、『約分後の』という記述に注意できていれば間違うことはありませんが、『符号付き32bit整数の範囲』の部分しか見ていないと、計算途中で範囲を超えてしまうことに気付かないか、そのようなデータはあり得ないと思い込んでしまいがちです。


全データはこちらからダウンロードできるようにしておきますので、全問正解ではなかった方、今回参加しなかった方も良ければ確認してみてください。

ちゃんとコーダーの皆さん

上記のテストケースをすべてクリアした挑戦者は、25名でした。おめでとうございます!!

全問正解者(25/79名、敬称略)
naoya_t
hogeover30
ushsh
ciel
じゃい
ayuzak
thasodahn
okzk
mkiken
rotary-o
アライブライム
folsena
yukim
mamekin
climpet
kuuso
sch
pepshiso
hm001
minghai
YuukiARIA
そらまめ
debiru
Azicore
TheO

※提出の早い順に掲載しています。

本の当選者は…

上記の25名に、1から25番までの番号を付けて次のスクリプトを実行しました。

3.times{p rand(25)+1}

結果、

11
7
14

と出力されましたので、当選者はthasodahnさん、アライブライムさん、mamekinさんということになりました。おめでとうございます!!詳細は、後から連絡されると思います。

オマケ1(統計情報)

f:id:codeiq:20130618173203p:plain
f:id:codeiq:20130618173210p:plain

オマケ2(Cの解答例)

#include <stdio.h>

#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )

unsigned int gcd(unsigned int a, unsigned int b)
{
  if( b==0 ) return 1;
  unsigned int m = a % b;
  if( m == 0 ) return b;
  return gcd( b, m );
}

int main()
{
  int a, b, c, d;
  int n;
  
  scanf("%d",&n);
  for(int i=0; i<n; ++i){
    scanf("%d%d%d%d", &a, &b, &c, &d );
    if( a == c ){
      printf("impossible\n");
      continue;
    }
    
    if( b == d ){
      printf("x = 0\n");
      continue;
    }
    
    // 符号
    int plus;
    if( ( a > c && d > b ) || ( a < c && d < b ) ){
      plus = 1; // +
    }else{
      plus = 0; // -
    }
    
    unsigned int p = a > c ? a - c : c - a;
    unsigned int q = d > b ? d - b : b - d;
    unsigned u = gcd( MAX(p,q), MIN(p,q) );
    
    p /= u;
    q /= u;
    
    if( p == 1 ){
      printf(plus ? "x = %u\n" : "x = -%u\n", q );
    }else{
      printf(plus ? "x = %u/%u\n" : "x = -%u/%u\n", q, p );
    }
  }
  
  return 0;
}

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

みなさん、ちゃんとコーディング、ちゃんとできましたか?
最高得点を出した25名の方には、のちほど、ちゃんどコーディングバッジを付与いたしますー。

問題文はこちらから。

https://codeiq.jp/ace/ozy4dm/q329
f:id:codeiq:20130618180318p:plain

CodeIQ中の人の一言:今日はCodeIQのお誕生日。BBQパーティーをしたのですが、お店がワンコをいっぱい飼っていて庭を走り回っていました。ソーセージをワンコに食べられるハプニングがあったり、CodeIQの挑戦者の突然の参加もあったりで、賑やかなランチタイムでありました。

エンジニアのための新しい転職活動!CodeIQのウチに来ない?の特集ページを見る