Atcoder を解く(ABC001)

ABC001 を解く

c++ で解いてます。理由は先輩が c++ は最高の言語だというからです。

問題A

簡単な引き算なので省略

問題B

まだできてマシェん

#include <iostream>
#include <sstream>

using namespace std;
 
int main()
{
    float d;
    std::stringstream stream;
    cin >> d;
    d /= 1000;
    if (d < 0.1)
    {
        cout << "00" << endl;
    }
    else if (0.1 <= d && d <= 5)
    {
        d *= 10;
        if (d < 10)
        {
            stream << "0" << d;
            cout << stream.str() << endl;
        }
        else
        {
            cout << d << endl;
        }
    }
    else if (6 <= d && d <= 30)
    {
        cout << d + 50 << endl;
    }
    else if (35 <= d && d <= 70)
    {
        cout << (d - 30) / 5 + 80 << endl;
    }
    else if (75 <= d)
    {
        cout << "89" << endl;
    }
    return 0;
}

test_09.txt と test_32.txt だけ解けない!

問題C

この問題はやることが大きく分けて二つあるって、
①.与えられた角度を元に方角出すこと。
②.与えられた風程を元に風力階級を出すこと。
だと考えました。

それぞれ分けて考えていきます。

①のやーつ

考え方

問題の条件を見ると、風向きが本来の角度を 10倍した整数で与えられる とあったので「それをさらに10倍して最大で5桁の数字(例:360度 -> 36000)になるようにしよう」と思いました。なぜなら、そのほうが計算しやすいからです。

そしてそのあとすぐ、value に方位(N~NNWの16個)を持つ配列を用意しようと思いました。

    string direction[size];

    direction[0] = "N";
    direction[1] = "NNE";
    direction[2] = "NE";
    direction[3] = "ENE";
    direction[4] = "E";
    direction[5] = "ESE";
    direction[6] = "SE";
    direction[7] = "SSE";
    direction[8] = "S";
    direction[9] = "SSW";
    direction[10] = "SW";
    direction[11] = "WSW";
    direction[12] = "W";
    direction[13] = "WNW";
    direction[14] = "NW";
    direction[15] = "NNW";

で、次に方位を示すインデックスを返す関数を考えました。 その際ににまず、頭の中に方位を表すマップを想像しました。 すると、下の図の赤の線を基準線にして 0度 としたとき、N が 基準線を包含していることに気づきました。

f:id:bitsukun75:20190330184357j:plain

このままだと、例えば 358度も 5度も同じ Nであるので計算がしづらいので基準線に合わせるように方位マップを時計回りに回転させました。言い換えれば、基準線に Nの左端を を一致させました。上の画像で 基準線より左方向にはみ出していたNは 11.25 度分なので 11.25度時計回りに回転させます。

その時の頭の中の図が下で

f:id:bitsukun75:20190330190412j:plain

コードに置き換えたのが下です。adjust 関数全体が上の画像で行なっている内容を実装しています。

void adjust(int *a)
{
    *a *= 10; // 計算しやすいように10倍する。
    if (*a > 34875) // 基準線をN極の左端に置いたので、それに一致させるよう角度も変化させる。(360000 - 1125 = 34875)
    {
        *a -= 34875;
        return;
    }
    else
    {
        *a += 1125;
        return;
    }
    return;
}

あとは、先ほど用意した配列と adjust させた角度の関連付けるんですがここが一番悩みました。アイデアが浮かばなかったんです。

結論は「角度 x から 1 方位分の 11.25 度を n 回 引く。n を配列のキーとする。」で方位をあらわそうと思いました。例えば、与えられた風向きが 275度 であれば、275から11.25 を 13 回引けるので それを配列のキーとして指定すれば方位が出ると思いました。

上に対応する関数が下です。

int calDeg(int a, int size)
{
    int i, b;
    adjust(&a);

    for (i = 1; i < size + 1; ++i)
    {
        b = a - i * 2250;
        if (b < 0)
        {
            return i - 1;
        }
    }
    return 0;
}

以上を組み合わせて下を作り、サンプルテキストを流し込んでみたら上手いこと言ったので「①.与えられた角度を元に方角出すこと。」の要件は満たしました。

#include <iostream>
using namespace std;

void adjust(int *a)
{
    *a *= 10;
    if (*a > 34875)
    {
        *a -= 34875;
        return;
    }
    else
    {
        *a += 1125;
        return;
    }
    return;
}

int calDeg(int a, int size)
{
    int i, b;
    adjust(&a);

    for (i = 1; i < size + 1; ++i)
    {
        b = a - i * 2250;
        if (b < 0)
        {
            return i - 1;
        }
    }
    return 0;
}

int main()
{
    int deg, size = 16, n;
    cin >> deg;
    string direction[size];

    direction[0] = "N";
    direction[1] = "NNE";
    direction[2] = "NE";
    direction[3] = "ENE";
    direction[4] = "E";
    direction[5] = "ESE";
    direction[6] = "SE";
    direction[7] = "SSE";
    direction[8] = "S";
    direction[9] = "SSW";
    direction[10] = "SW";
    direction[11] = "WSW";
    direction[12] = "W";
    direction[13] = "WNW";
    direction[14] = "NW";
    direction[15] = "NNW";

    cout << direction[calDeg(deg, size)] << endl;
}

②のやーつ

よっし、次は②です。その前に風呂入ってきます。

詰まったとこ

負の数は true

C++ では 0, null pointer value, null member pointer value 以外は全て true で評価されるんですねー。

Javascript 触ってた癖で 0false だと思い込んでいました。( ;∀;)

4.12 Boolean conversions [conv.bool] 1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.5), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false. (C++ 基準より引用)

証明

    int a = -1;
    if (a)
    {
        cout << "negative number is true" << endl; 
    }
    else
    {
        cout << "negative number is false" << endl;
    }

// => negative number is true

おことわり

Terms of service - AtCoder より 自分に著作権が属するもののみブログに表示しています。 よって問題文は表示しません。