C++
 Computer >> コンピューター >  >> プログラミング >> C++

特定の操作で各都市から訪問できる都市の数を数えるC++プログラム

問題の概要

N個の座標点Pが (xi, yi) の形式で与えられているとします。ここで、xとyの値はそれぞれ1からNまでの自然数の順列になっています。

1からNまでの各kについて、自分は今「都市k」にいるものと考えます。次の操作を任意の回数だけ繰り返し実行できます。

操作: 現在いる都市と比較して、「x座標とy座標の両方が小さい都市」または「x座標とy座標の両方が大きい都市」へ移動する。

このとき、都市kから到達できる都市の総数を求めるのが目的です。

例えば、入力が P = [[1, 4], [2, 3], [3, 1], [4, 2]] の場合、出力は [1, 1, 2, 2] となります。

解き方のアプローチ

この問題を解くために、以下の手順に従います。

  • x座標を基準にすべての都市をソートします。
  • 先頭から順に都市を見ていきながら、それまでに処理した都市の中での最小のy座標(y_min)を追跡します。
  • y_min + i が n と等しくなった時点で、それまでに集めた都市のグループは外部のどの都市にも移動できない「閉じたグループ(連結成分)」になります。これは、残りの都市がすべて現在のグループより小さなy座標を持つためです。
  • 閉じたグループが確定したら、グループ内の全都市の答えをグループのサイズとして記録し、集合をクリアします。
n := size of P
Define one 2D array lst
for initialize i := 0, when i < n, update (increase i by 1), do:
   v := { P[i, 0], P[i, 1], i }
   insert v at the end of lst
sort the array lst
y_min := 1e9
Define one set se
Define an array ans of size n and fill with 0
for initialize i := 0, when i < n, update (increase i by 1), do:
   y_min := minimum of y_min and lst[i, 1]
   insert lst[i, 2] into se
   if y_min + i is same as n, then:
      for each element j in se
         ans[j] := size of se
      clear the set se
   if i is same as n - 1, then:
      for each element j in se
         ans[j] := size of se
for initialize i := 0, when i < n, update (increase i by 1), do:
   display ans[i]

C++による実装例

理解を深めるために、以下の実装例を見てみましょう。

#include <bits/stdc++.h>
using namespace std;

void solve(vector<vector<int>> P){
   int n = P.size();
   vector<vector<int>> lst;
   for (int i = 0; i < n; i++){
      vector<int> v = { P[i][0], P[i][1], i };
      lst.push_back(v);
   }
   sort(lst.begin(), lst.end());
   int y_min = 1e9;
   set<int> se;
   vector<int> ans(n, 0);
   for (int i = 0; i < n; i++){
      y_min = min(y_min, lst[i][1]);
      se.insert(lst[i][2]);
      if (y_min + i == n){
         for (auto j : se)
            ans[j] = se.size();
         se.clear();
      }
      if (i == n - 1){
         for (auto j : se)
            ans[j] = se.size();
      }
   }
   for (int i = 0; i < n; i++){
      cout << ans[i] << ", ";
   }
}
int main(){
   vector<vector<int>> P = { { 1, 4 }, { 2, 3 }, { 3, 1 }, { 4, 2 } };
   solve(P);
}

入力

{ { 1, 4 }, { 2, 3 }, { 3, 1 }, { 4, 2 } }

出力

1, 1, 2, 2,
  1. サイズ d の正十二角形を作れる組み合わせの数を求める C++ プログラム

    問題概要 整数 d が与えられたとします。ここで、一辺の長さが 1 の正方形タイルと正三角形タイルが無限枚あるものと考えます。これらのタイルを組み合わせて、一辺の長さが d の正十二角形(12 辺形)を作るとき、その作り方が何通りあるかを求めるのがこの問題です。答えが非常に大きくなる場合は、998244353 で割った余りを返します。 アプローチ この問題は、二項係数を利用することで効率的に解くことができます。結論から言うと、求めるべき答えは C(2d−1, d−1)、すなわち「2d−1 個の中から d−1 個を選ぶ組み合わせの総数」です。 階乗を直接計算すると値が急激に大きくなりオーバー

  2. 【C++】バイナリ行列をすべて0に変換するための最小操作回数を求めるプログラム

    問題概要0と1のみから構成されるバイナリ行列が与えられます。使用できる操作は「任意の1つのセルを選び、そのセル自身と上下左右の隣接するセル(存在する場合のみ)をすべて反転(0→1、1→0)する」というものです。この操作を繰り返して行列の全要素を0にするために必要な最小操作回数を求めてください。どのように操作してもすべて0にできない場合は -1 を返します。入力例{{0, 0}, {1, 0}}これは次のような2×2の行列です。0010出力3この場合、必要な操作回数は3回となります。解法のアプローチこの問題は、行列の状態をビットマスク(整数)として表現し、幅優先探索(BFS)で最短操作回数を求め