特定の操作で各都市から訪問できる都市の数を数える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,
-
サイズ d の正十二角形を作れる組み合わせの数を求める C++ プログラム
問題概要 整数 d が与えられたとします。ここで、一辺の長さが 1 の正方形タイルと正三角形タイルが無限枚あるものと考えます。これらのタイルを組み合わせて、一辺の長さが d の正十二角形(12 辺形)を作るとき、その作り方が何通りあるかを求めるのがこの問題です。答えが非常に大きくなる場合は、998244353 で割った余りを返します。 アプローチ この問題は、二項係数を利用することで効率的に解くことができます。結論から言うと、求めるべき答えは C(2d−1, d−1)、すなわち「2d−1 個の中から d−1 個を選ぶ組み合わせの総数」です。 階乗を直接計算すると値が急激に大きくなりオーバー
-
【C++】バイナリ行列をすべて0に変換するための最小操作回数を求めるプログラム
問題概要0と1のみから構成されるバイナリ行列が与えられます。使用できる操作は「任意の1つのセルを選び、そのセル自身と上下左右の隣接するセル(存在する場合のみ)をすべて反転(0→1、1→0)する」というものです。この操作を繰り返して行列の全要素を0にするために必要な最小操作回数を求めてください。どのように操作してもすべて0にできない場合は -1 を返します。入力例{{0, 0}, {1, 0}}これは次のような2×2の行列です。0010出力3この場合、必要な操作回数は3回となります。解法のアプローチこの問題は、行列の状態をビットマスク(整数)として表現し、幅優先探索(BFS)で最短操作回数を求め