AtCoder

ABC270 B問題(Hammer)を解く

AtCoder が提供しているABC(AtCoder Beginner Contest)270 のB問題をC++とPythonで解いてみました。ABC270は、2022年9月24日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

B問題 Hammer(Difficulty : 106)

問題はリンク先をご覧ください。

ABC270 B問題 Hammer

条件分岐を漏れなく抽出していく必要があります。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 の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA