C++で全ての点を訪問するための最小時間を求めるアルゴリズム
配列として与えられた複数の点(座標)があります。このとき、すべての点を訪問するのに必要な最小時間(秒)を求める問題を考えます。ただし、以下の条件が課せられています。
- 1秒につき、上下・左右・斜めのいずれかの方向へ1マス移動できる
- 点は配列に現れる順序どおりに訪問しなければならない
例えば、点が [(1, 1), (3, 4), (-1, 0)] と与えられた場合、出力は 7 になります。最短経路をたどる際の移動の順序は、(1, 1) → (2, 2) → (3, 3) → (3, 4) → (2, 3) → (1, 2) → (0, 1) → (-1, 0) となります。
解き方のアプローチ
この問題を解く鍵となるのは、チェビシェフ距離(Chebyshev distance) の考え方です。斜め移動が許されているため、隣接する2点間を移動するのに必要な秒数は、「X座標の差の絶対値」と「Y座標の差の絶対値」のうち大きい方と一致します。これは、斜めに移動すればX方向とY方向を同時に進めるためです。
したがって、連続する2点ごとにX座標の差とY座標の差を計算し、その最大値を順番に加算していくだけで答えが求まります。計算量は O(n) と非常に効率的です。
実装例
以下はC++による実装例です。
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int minTimeToVisitAllPoints(vector<vector<int>>& p) {
int ans = 0;
int n = p.size();
for(int i = 1; i < n; i++){
ans += max(abs(p[i][0] - p[i-1][0]), abs(p[i][1] - p[i-1][1]));
}
return ans;
}
};
main(){
Solution ob;
vector<vector<int>> c = {{1,1},{3,4},{-1,0}};
cout << ob.minTimeToVisitAllPoints(c);
}入力
[[1,1],[3,4],[-1,0]]
出力
7
このように、各2点間の移動コストを max(|dx|, |dy|) で求めて合計するだけで、斜め移動を活用した最短時間を簡単に計算できます。
-
C++で解くナイトの最短移動回数問題:メモ化再帰による効率的な解法
問題概要無限に広がるチェス盤を考えます。座標は -∞ ~ +∞ の範囲に及び、ナイトは初期状態でマス [0, 0] に配置されています。ナイトの移動は下図のように8通りあり、それぞれ「縦または横の方向に2マス、その後それと直交する方向に1マス」という動きになります。この問題では、ナイトを目標のマス [x, y] まで移動させるのに必要な最小手数を求めます。なお、必ず目的地に到達できる(解が存在する)ことが保証されています。具体例たとえば入力が x = 5、y = 5 の場合、出力は 4 になります。これは次のような経路で到達できるためです。[0,0] → [2,1] → [4,2] → [3,
-
C++で全従業員に緊急ニュースを伝えるのに必要な時間を求める方法(BFS活用)
問題の概要ある会社にはn人の従業員が在籍しており、各従業員には0からn-1までの一意なIDが割り振られています。会社のトップ(社長)はheadIDで表されます。各従業員には必ず一人の直属の上司が存在し、それはmanager配列によって与えられます。manager[i]はi番目の従業員の直属の上司を意味し、社長の場合はmanager[headID] = -1となります。なお、組織の上下関係は木構造になっていることが保証されています。社長は緊急のニュースを全従業員に伝えたいと考えています。まず社長が直属の部下に連絡し、その部下たちがさらに自分の部下へと伝えていくことで、ニュースは組織全体へと広まっ