C - 温度調整の最小コスト / Minimum Cost of Temperature Adjustment 解説 by admin
Gemini 3.0 Flash概要
数直線上の \(0\) の地点から出発し、与えられた \(N\) 個の地点(温度 \(H_i\))をすべて訪れてから再び \(0\) に戻るまでの、最短移動距離を求める問題です。
考察
この問題は、「数直線上の複数の点をすべて回って元の場所に戻る」という設定に置き換えて考えることができます。
重要な気づき
数直線上の点(温度)を効率よく回るためには、あちこちを行ったり来たりするのではなく、端から端まで一気に移動するのが最も効率的です。
- 訪れるべきすべての地点(試薬の温度 \(H_1, \dots, H_N\))と、開始・終了地点である \(0\) を合わせた集合を考えます。
- この集合の中の最小値を \(min\_temp\)、最大値を \(max\_temp\) とします。
- どのような順番で回ったとしても、すべての地点を訪れて \(0\) に戻るためには、少なくとも \(min\_temp\) から \(max\_temp\) までの区間を「往復」する必要があります。
なぜ「(最大値 - 最小値) × 2」になるのか?
例えば、温度が \(\{-5, 10\}\) で開始地点が \(0\) の場合を考えます。 - 訪れるべき点は \(\{-5, 0, 10\}\) です。 - 最小値は \(-5\)、最大値は \(10\) です。 - 最短経路の例: \(0 \to -5 \to 10 \to 0\) - 移動距離: \(|-5 - 0| + |10 - (-5)| + |0 - 10| = 5 + 15 + 10 = 30\) - これは、\((10 - (-5)) \times 2 = 15 \times 2 = 30\) と一致します。
数直線上の最も左にある点から最も右にある点まで移動し、そこから戻ってくることで、その間にあるすべての点は必ず通過することになります。したがって、最適な戦略は「左端まで行って右端まで行く(またはその逆)」となり、その合計距離は「(最大値 - 最小値)の2倍」となります。
アルゴリズム
- 与えられた \(N\) 個の温度 \(H_i\) に、開始地点である \(0\) を加えたリストを作成します。
- そのリストの中から最大値 \(max\_temp\) と最小値 \(min\_temp\) を見つけます。
- 提供されたコードでは、ソート(
sorted)を行うことで、最初の要素を最小値、最後の要素を最大値として取得しています。
- 提供されたコードでは、ソート(
- \((max\_temp - min\_temp) \times 2\) を計算して出力します。
計算量
- 時間計算量: \(O(N \log N)\)
- \(N\) 個の要素のソートに \(O(N \log N)\) かかります。
- ※単に最大値と最小値を求めるだけであれば \(O(N)\) で解くことも可能です。
- 空間計算量: \(O(N)\)
- 入力された \(N\) 個の温度を保持するために \(O(N)\) のメモリを使用します。
実装のポイント
開始地点 \(0\) の扱い: 試薬の温度がすべて正の場合や、すべて負の場合があります。その場合でも必ず \(0\) に戻る必要があるため、最大値・最小値を判定する対象に \(0\) を含めることが必須です。
重複の削除: 提供されたコードでは
setを使用して重複を削除しています。計算量に大きな影響はありませんが、メモリの節約や処理の整理に役立ちます。ソースコード
import sys
def main():
# 標準入力からすべてのデータを読み込み、トークンに分割します
# この手法は大量の入力を効率的に処理するのに適しています
input_data = sys.stdin.read().split()
if not input_data:
return
# 試薬の温度設定(H_i)を整数に変換し、セット(集合)に格納します
# また、開始点および終了点である「0度」を必ず含めるようにします
# セットを使用することで重複する温度を1つにまとめ、処理を効率化します
temp_points = set(map(int, input_data[1:]))
temp_points.add(0)
# 温度の集合を昇順にソートします
# 0度を含めた全温度を訪問して0度に戻るための最小コストは、
# 数直線上の「最も低い温度」から「最も高い温度」までの距離の2倍になります
sorted_points = sorted(temp_points)
# ソートされたリストの最初(最小値)と最後(最大値)の要素から全範囲を求めます
# 0がリストに含まれているため、この範囲は必ず開始点と終了点をカバーします
min_temp = sorted_points[0]
max_temp = sorted_points[-1]
# 全移動距離(エネルギー消費量の合計)は (最大温度 - 最小温度) * 2 です
# 既存のループによる最大・最小値探索とは異なり、ソートを利用したアプローチです
print((max_temp - min_temp) * 2)
if __name__ == "__main__":
main()
この解説は gemini-3-flash-preview によって生成されました。
投稿日時:
最終更新: