AtCoder が提供しているABC(AtCoder Beginner Contest)270 のB問題をC++とPythonで解いてみました。ABC270は、2022年9月24日21:00に実施されました。
AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。
B問題 Hammer(Difficulty : 106)
問題はリンク先をご覧ください。
条件分岐を漏れなく抽出していく必要があります。AtCoder Problems による Difficulty は、106 でした。
解答案
問題を解く方針を書きだします。
- 3つの整数 X(ゴール)、Y(壁)、Z(ハンマー)を標準入力から読み取る。
- 条件を整理します。
- ハンマーを使わない場合
- X が正の数で、Y が X より大きい場合(0 < X < Y)、移動距離は、X となる。
- X が正の数で、Y が負の数の場合も(Y < 0 < X)、移動距離は、X となる。
- X が負の数で、Y が X より小さい場合(Y < X < 0)、移動距離は、-X となる。
- X が負の数で、Y が正の数の場合も(X < 0 < Y)、移動距離は、-X となる。
- ハンマーを使う場合
- X が正の数で、Y が X より小さい場合(0 < Y < X)、Z が Y との間にあれば(0 < Z < Y)、移動距離は、X となる。
- X が正の数で、Y が X より小さい場合(0 < Y < X)、Z が負の数であれば、ハンマーを取りにいくため、移動距離は、2 × -Z + X となる。
- X が負の数で、Y が X より大きい場合(X < Y < 0)、Z が Y との間にあれば(Y < Z < 0)、移動距離は、-X となる。
- X が負の数で、Y が X より大きい場合(X < Y < 0)、Z が正の数であれば、ハンマーを取りにいくため、移動距離は、2 × Z + -X となる。
- それ以外の場合
- この場合は、X(ゴール)との間に Y(壁)があり、Z(ハンマー)が壁より遠くにあるため、ゴールにたどり着けない。
- ハンマーを使わない場合
X、Y、Z が正の数の場合と負の数の場合があり、場合分けが複雑になりました。上の条件分岐を、そのままプログラムしました。
C++ プログラム例(ABC270B)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, z;
cin >> x >> y >> z;
if ((0 < x)&&(x < y)) {
cout << x << endl;
return 0;
}
if ((0 < x)&&(y < 0)) {
cout << x << endl;
return 0;
}
if ((x < 0)&&(y < x)) {
cout << -x << endl;
return 0;
}
if ((x < 0)&&(0 < y)) {
cout << -x << endl;
return 0;
}
if ((0 < x)&&(y < x)) {
if ((0 < z)&&(z < y)) {
cout << x << endl;
return 0;
}
if (z < 0) {
cout << 2 * -z + x << endl;
return 0;
}
}
if ((x < 0)&&(x < y)) {
if ((z < 0)&&(y < z)) {
cout << -x << endl;
return 0;
}
if (z > 0) {
cout << 2 * z + -x << endl;
return 0;
}
}
cout << -1 << endl;
return 0;
}
条件分岐が多いプログラムですが、AC(Accepted=正しいプログラム)と判定されました。
AtCoder では、コンテスト後に解説が公開されます。以下のようにうまく条件を整理していました。
- 最初に Y が負の場合は、X、Y、Z の符号を反転して、常に Y を正の数とする。
- X が Y より小さい場合は、X の正負に関わらず、移動距離は、X の絶対値(abs(X))となる。
- X が Y より大きい場合は、Z(ハンマー)の位置で場合分けする。
- Z が Y より大きい場合は、ハンマーを取ることができず、ゴールにたどりつけない。
- Z が Y より小さい場合は、ハンマーを取り、ゴールに向かう、その移動距離は、それぞれ 0 と Z の距離と、X と Z の距離の和になる。
この条件分岐に従いプログラムしました。すっきり書けています。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, z;
cin >> x >> y >> z;
if (y < 0) {
x = -x;
y = -y;
z = -z;
}
if (x < y) {
cout << abs(x) << endl;
return 0;
} else if ((y < x)&&(y < z)) {
cout << -1 << endl;
return 0;
} else {
cout << abs(z) + abs(x - z) << endl;
return 0;
}
}
このプログラムも、当然 AC(Accepted=正しいプログラム)と判定されました。
Python プログラム例(ABC270B)
Python でも書いてみました。基本的には、C++ をそのまま Python に落とし込んだプログラムになっています。論理AND演算子は、’&&’ ではなく、and になります。
"""AtCoder Beginner Contest 270 B"""
x, y, z = map(int, input().split())
if y < 0:
x, y, z = -x, -y, -z
result = 0
if x < y:
result = abs(x)
elif y < x and y < z:
result = -1
else:
result = abs(z) + abs(x - z)
print(result)
Python 版も「AC」と判定されました。
最後に
自分なりに条件分岐を考えて実装しました。公式解説では、すっきりと解決できていまいた。その差を自分なりに理解して消化していくと、実装する力が伸びていくと考えています。
引き続き ABC の問題を紹介していきます。