【C++解説】AtCoder Beginner Contest 001-B – 視程の通報【競技プログラミング】
本日の問題
今回はAtCoder Beginner Contest 001のB問題視程の通報を解いていきます。
※YouTubeに解説動画あります。
問題文を要約すると、視程(肉眼で物体がはっきりと確認できる最大の距離)をメートルで受け取り、以下のルールに従ってVVという2桁の整数に変換して出力するプログラムを作る問題です。
- 0.1km 未満:VVの値は
00とする。 - 0.1km 以上 5km 以下:距離(km)を10倍した値とする。1桁の場合は上位に
0を付す。- 例:2,000m = 2.0km → VVは
20。200m = 0.2km → VVは02。
- 例:2,000m = 2.0km → VVは
- 6km 以上 30km 以下:距離(km)に50を足した値とする。
- 例:15,000m = 15km → VVは
65。
- 例:15,000m = 15km → VVは
- 35km 以上 70km 以下:距離(km)から30を引いて5で割った後、80を足した値とする。
- 例:40,000m = 40km → VVは
82。
- 例:40,000m = 40km → VVは
- 70km より大きい:VVの値は
89とする。
入力は距離 m(0 ≦ m ≦ 100,000)が1行で与えられ、計算結果が整数にならない入力や、上記範囲に入らない入力(例:5kmより大きく6km未満)はないことが保証されています。
※https://atcoder.jp/contests/abc001/tasks/abc001_2
解説
一番オーソドックスなif文で条件を全て書き出すと以下のようになります。
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int m;
cin >> m;
int vv;
if (m < 100) { // 0.1km 未満
vv = 0;
} else if (m <= 5000) { // 0.1km 以上 5km 以下: km×10 = m/100
vv = m / 100;
} else if (m <= 30000) { // 6km 以上 30km 以下: km+50
vv = m / 1000 + 50;
} else if (m <= 70000) { // 35km 以上 70km 以下: (km-30)/5+80
vv = (m / 1000 - 30) / 5 + 80;
} else { // 70km より大きい
vv = 89;
}
cout << setw(2) << setfill('0') << vv << endl;
return 0;
}もう一つの書き方として、三項演算子(?:)を使って条件分岐をスッキリ書くことができます。
三項演算子(?:)の基本
三項演算子は「条件式 ? 真の場合の値 : 偽の場合の値」という形をとります。if-else文を1行で書けるコンパクトな書き方です。
条件式 ? 真の場合の値 : 偽の場合の値
// 基本形
条件式 ? 真の場合の値 : 偽の場合の値
// 例
int x = (a < b) ? a : b; 今回の条件で三項演算子を使ってみると以下のようになります
int vv =
m < 100 ? 0 :
m <= 5000 ? m / 100 :
m <= 30000 ? m / 1000 + 50 :
m <= 70000 ? (m / 1000 - 30) / 5 + 80 : 89;m < 100→ true →0を代入して終了- 2.ダメなら
m <= 5000→ true →m / 100を代入して終了 - 3.ダメなら
m <= 30000→ true →m / 1000 + 50を代入して終了 - 4.ダメなら
m <= 70000→ true →(m / 1000 - 30) / 5 + 80を代入して終了 - 5.全部ダメなら
89を代入
三項演算子は簡潔に書けますが、条件を間違えやすい欠点もあります。
慣れないうちはif-elseで書き、コードに慣れてきたら三項演算子も使ってみるのがお勧めです。
最後に今回の問題の出力について解説します。
cout << setw(2) << setfill('0') << vv << endl;この1行で「VVの値を2桁のゼロ埋め付きで出力し、改行する」という処理を行っています。問題文で「VVは必ず(上位の 0 を含めて)2桁の整数」と指定されているため、02 のように1桁の値には先頭に 0 を付ける必要があります。
各部分の役割
setw と setfill を使うには <iomanip> のインクルードが必要です。
#include <iomanip>※iomanip は io(I/O=入出力)+ manip(manipulator=操作子)の組み合わせで、「入出力を操作するためのヘッダ」という意味です。
1行ずつ分解すると以下のようになります。
| 部分 | 役割 | 詳細 |
|---|---|---|
cout | 標準出力 | 画面への出力を行う |
setw(2) | 出力幅を2に指定 | 次に出力する値を最低2桁で表示する(※set width) |
setfill('0') | ゼロ埋め | 桁が足りない部分を 0 で埋める |
setw(2) だけだと空白埋め( 2)になってしまうので、setfill('0') と組み合わせてゼロ埋め(02)にしています。

