C++

 Computer >> コンピューター >  >> プログラミング >> C++
  1. C++で数値に最も近い回文数を求めるアルゴリズムと実装例

    問題の概要 ある数値 n が与えられたとき、それに最も近い回文数(前から読んでも後ろから読んでも同じ並びになる数)を求める問題を考えます。「近さ」は絶対差で評価し、n より小さい回文でも大きい回文でも、差がより小さい方を採用します。 たとえば入力が 145 の場合を考えてみましょう。 下側の回文 141 との差は 4、上側の回文 151 との差は 6 です。差がより小さいのは 141 なので、答えは 141 になります。 解法の方針 すべての数を順番に調べて回文かどうか判定する方法は非効率です。そこで、「最も近い回文となり得る候補」だけを少数ピックアップして比較します。候補となるのは次のパタ

  2. C++で二進表現に連続する1を含まない非負整数の個数を求める方法

    正の整数 n が与えられたとき、n 以下の非負整数のうち、二進表現に「1」が連続して現れないものの個数を求める問題を考えます。例えば入力が 7 の場合、答えは 5 になります。これは、7 以下で条件を満たす整数が 0(0)、1(1)、2(10)、4(100)、5(101)の 5 個しか存在しないためです。3(11)、6(110)、7(111)は「1」が連続しているため除外されます。 解法のアプローチ この問題は、桁ごとの動的計画法(DP)を用いることで効率的に解けます。各桁について「その桁が 0 で終わるパターン数」と「1 で終わるパターン数」を管理し、実際のビット列と照らし合わせながら答えを

  3. C++で解く「K逆ペア配列」問題 ― 動的計画法による効率的な解法

    問題概要2つの整数 n と k が与えられます。1 から n までの数字をそれぞれ1回ずつ使って構成される配列のうち、逆ペア(転倒ペア)がちょうど k 個含まれるものが何通り存在するかを求めてください。ここで、逆ペアとは配列中の i 番目と j 番目の要素について、i < j かつ a[i] > a[j] が成り立つペアのことを指します。答えは非常に大きな値になる可能性があるため、109 + 7 で割った余りを返します。例えば、n = 3、k = 1 の場合、出力は 2 になります。これは [1, 3, 2] と [2, 1, 3] の2つの配列が、それぞれちょうど1つの逆ペアを持

  4. C++でk個のソート済みリストをカバーする最小範囲を求めるアルゴリズム

    この記事では、k個のソートされた整数リストが与えられたときに、各リストから少なくとも1つの数値を含む最小の範囲を求める問題について解説します。ここで、範囲[a, b]が範囲[c, d]より「小さい」とは、次のいずれかの条件を満たす場合を指します。b − a < d − c(幅が狭い)b − a == d − c かつ a < c(幅が同じ場合は開始位置が小さい方)入力と出力の例たとえば、入力が以下のような3つのリストだったとします。[[4,10,15,25,26], [0,9,14,20], [5,18,24,30]]この場合、出力は [14, 18] となります。14は2番目のリ

  5. C++で解く「デコード方法 II」― ワイルドカード(*)を含む文字列の復号パターン数を求める

    A〜Zの英字からなるメッセージが、次のようなマッピング規則に従って数字へエンコードされていると仮定します。 A → 1、B → 2、…、Z → 26 さらに、エンコードされた文字列には * という特殊な文字が含まれることがあります。* は 1 から 9 までのいずれかの数字として扱えます。したがって、数字と * を含むエンコード済みメッセージが与えられたとき、そのメッセージをデコードできる方法の総数を求めるのがこの問題です。答えが非常に大きな値になる可能性があるため、最終的な結果は 109 + 7 で割った余りを返します。 たとえば入力が * だけの場合、考えられるデコード方法は 9 通りあ

  6. C++で解く「奇妙なプリンター」問題 ― 区間DPで最小ターン数を求める

    奇妙なプリンター問題とは「奇妙なプリンター(Strange Printer)」は、次のような制約を持つ架空の印刷装置に関する問題です。1回の操作で印刷できるのは、同じ文字が連続した列のみである。各ターンでは、好きな開始位置から好きな終了位置まで新しい文字を印刷でき、すでに印刷済みの文字は上書きされる。小文字アルファベットのみで構成された文字列が与えられたとき、この文字列を完成させるまでに必要な最小ターン数を求めるのが課題となります。たとえば入力が「aaabba」の場合、答えは2ターンです。まず「aaaaaa」と全体をaで印刷し(1ターン目)、続いて該当する位置をbで上書きすれば(2ターン目)、

  7. C++で九九表のK番目に小さい数を二分探索で効率的に求める方法

    掛け算の九九表は誰もが知っていますが、その中からk番目に小さい数を素早く見つけられるでしょうか。本記事では、高さm・幅nのm×nの九九表と正整数kが与えられたとき、表の中でk番目に小さい数を求めるアルゴリズムをC++で解説します。問題の例例えば、m = 3、n = 3、k = 6の場合、出力は4となります。このときの九九表は以下の通りです。123112322463369表の要素を昇順に並べると [1, 2, 2, 3, 3, 4, 6, 6, 9] となるため、6番目に小さい要素は4であることが分かります。解法のアプローチ:二分探索この問題は二分探索を使うことで効率的に解けます。まず、補助関数

  8. C++で解く24ゲーム:四則演算で24を作れるか判定するアルゴリズム

    問題の概要 1から9までのいずれかの数値が書かれたカードが4枚あるとします。これらの数値に対して「+(足し算)」「-(引き算)」「*(掛け算)」「/(割り算)」の四則演算を自由に組み合わせ、計算結果をちょうど24にできるかどうかを判定するのが、いわゆる「24ゲーム」と呼ばれる問題です。 たとえば、手元のカードが [4, 9, 2, 6] だった場合、(4 * 9) - (2 * 6) という式で 36 − 12 = 24 が求められるため、答えは true(24が作れる)となります。 解法のアプローチ:バックトラッキング この問題はバックトラッキング(試行錯誤しながら探索を進め、行き詰まっ

  9. C++で解く「冗長な接続 II」— 余分な有向エッジの検出アルゴリズム

    問題の概要根付き木(rooted tree)とは、次のような性質を持つ有向グラフのことです。すべてのノードがその子孫となる「根(ルート)」がちょうど1つ存在し、根以外のすべてのノードは親をちょうど1つ持ちます。根だけは親を持ちません。入力として与えられるのは、N個のノード(ノードの値はすべて一意)からなる根付き木に、有向エッジを1本追加した有向グラフです。追加されたエッジは1からNまでの中から選ばれた異なる2つの頂点を結ぶものであり、元の木には存在しなかったエッジです。グラフは2次元配列edgesで表現されます。edgesの各要素は[u, v]というペアで、ノードuからノードvへ向かう有向エッ

  10. C++で解く「3つの重ならない部分配列の最大合計」問題:累積和を使った効率的な実装

    正の整数からなる配列 nums が与えられたとき、合計が最大となる3つの重ならない部分配列を見つける問題を考えます。各部分配列の長さは k に固定されており、3 * k 個の要素全体の合計を最大化することが目標です。 答えは、各区間の開始位置を表すインデックスのリストとして返します。条件を満たす組み合わせが複数存在する場合は、辞書順で最小のものを返す必要があります。 たとえば、入力が [1,2,1,2,6,8,4,1]、k = 2 の場合、出力は [0,3,5] となります。これは、部分配列 [1,2]、[2,6]、[8,4] の開始インデックス [0,3,5] に対応しています。 アルゴリ

  11. C++でステッカーを使って目標の単語を綴る:必要な最小枚数を求めるビットDP解法

    問題概要 N種類の異なるステッカーがあるとしましょう。それぞれのステッカーには、小文字の英単語が1つ印刷されています。このステッカーのコレクションから個々の文字を切り取り、並べ替えることで、与えられたターゲット文字列を綴りたいと考えています。同じ種類のステッカーは必要に応じて何度でも使用でき、各ステッカーは無限枚用意されているものとします。 求めるのは、ターゲットを綴るために必要な最小のステッカー枚数です。もしターゲットを綴ることが不可能な場合は、-1を返してください。 たとえば、入力が [dog, sentence, antenna] で、ターゲットが dance の場合、答えは 3 になり

  12. C++でブラックリストを除外したランダム選択を実装する方法

    範囲 [0, N) に属する一意な整数を格納したブラックリスト B があるとします。ここで求めたいのは、[0, N) の範囲からブラックリストに含まれていない整数を一様な確率で返す関数です。さらに、rand() の呼び出し回数をできるだけ減らすことで、この関数を最適化することも目標とします。例えば、入力として次のようなデータが与えられたケースを考えてみましょう。 解法のアプローチ この問題を効率よく解く鍵となるのが「マッピング(対応表)」の考え方です。まず、実際に選択対象となる有効な数値の個数 M を事前に計算しておきます。そして、pick() が呼ばれた際には [0, M) の範囲でのみ乱

  13. C++で範囲モジュール(Range Module)を実装する方法

    数値の範囲(レンジ)を追跡する「範囲モジュール」を設計してみましょう。このモジュールは半開区間 [left, right) の形で数値の区間を管理し、以下の3つの操作を効率的に実行できることが求められます。 実装すべきインターフェース addRange(left, right):半開区間 [left, right) に含まれるすべての実数を追跡対象に追加します。既存の追跡区間と部分的に重なる場合でも、まだ追跡されていない部分だけが新たに追加されます。 queryRange(left, right):区間 [left, right) 内のすべての実数が現在追跡中であれば true を返します。

  14. 【C++】配列内のK番目に小さいペア距離を求める方法

    問題の概要整数型の配列が与えられたとき、すべてのペアの中からk番目に小さい距離を求めることを考えます。ここで、ペア (A, B) の距離とは、A と B の差の絶対値(|A − B|)を指します。例として、入力が [1, 3, 8] の場合を見てみましょう。考えられるすべてのペアとその距離は以下の通りです。[1, 3] → 距離 2[3, 8] → 距離 5[1, 8] → 距離 7このとき k = 2 であれば、2番目に小さい距離は 5(8 − 3)となります。解法のアプローチこの問題は、カウント配列(度数分布)を使ったシンプルな手法で解くことができます。手順は以下の通りです。配列のサイズを

  15. C++で解くチェリーピックアップ問題:往復移動でチェリーを最大化する動的計画法

    問題概要N × N のグリッドが与えられ、各マスにはチェリーが置かれています。マスに入っている値は次のいずれかです。0 ― マスは空であり、自由に通過できます1 ― マスにチェリーがあり、通過時に回収できます-1 ― マスにトゲがあり、通行を妨げられます以下のルールに従って、回収できるチェリーの数を最大化することを目指します。(0, 0) から出発し、「右」または「下」への移動のみで有効な経路をたどって (N-1, N-1) まで進む(N-1, N-1) に到達した後、今度は「左」または「上」への移動のみで (0, 0) まで戻るチェリーのあるマスを通ると、そのチェリーを回収し、そのマスは空(

  16. C++で金庫のパスワードをクラックするアルゴリズムと実装例

    パスワードで保護された金庫を想像してみてください。パスワードは n 桁の数字列で、各桁には 0 ~ k−1 までの先頭 k 個の数字(0, 1, …, k−1)のいずれかが使用されます。この金庫には特別な仕組みがあり、パスワードを入力すると、最後に入力された n 桁が自動的に正規のパスワードと照合されます。たとえば、正しいパスワードが「563」である場合、「285639」と入力すると、末尾の 3 桁「563」が正しいパスワードと一致するため、金庫は開きます。今回の目的は、入力中のいずれかの時点で確実に金庫が開く、最小長の数字列を 1 つ見つけることです。たとえば n = 2、k = 2 が与え

  17. C++で解く「上昇する水面を泳ぐ」問題(Swim in Rising Water)

    問題概要 N×N のグリッドが与えられ、各マス grid[i][j] には地点 (i, j) の標高が格納されています。ここで雨が降り始めたとしましょう。時刻 t において、グリッド上のどこでも水深は一様に t になります。隣接する2つのマスの標高がどちらも t 以下であれば、その間を上下左右の4方向へ移動(泳ぐ)することができ、移動にかかる時間はゼロ、つまり条件さえ満たしていれば無限の距離を瞬時に進めるものとします。 スタート地点は左上の (0, 0) です。右下のマス (N-1, N-1) に到達できる最短の時刻を求めてください。 入力例 012342423222151213151516

  18. C++で始点から目標点に到達できるかを判定するアルゴリズム

    始点 (sx, sy) と目標点 (tx, ty) が与えられたとき、始点から目標点へ至る一連の移動が存在するかどうかを判定する問題を考えます。ここでいう「移動」とは、現在の点 (x, y) を (x, x+y) または (x+y, y) のいずれかに変換する操作のことです。 例として、始点が (1, 1)、目標点が (4, 5) の場合をみてみましょう。このとき答えは true になります。(1,1) → (2,1) → (3,1) → (4,1) → (4,5) という移動列が存在するためです。 解法の考え方 この問題を前方向きに素朴にシミュレーションすると、座標が指数的に増大していき非

  19. C++で盤面をチェス盤に変換する:最小手数を求めるアルゴリズム

    問題概要 0と1のみで構成される N × N の盤面が与えられたとします。各操作では、任意の2つの行、または任意の2つの列を入れ替えることが可能です。このとき、盤面を「チェス盤」のパターンに変換するために必要な最小の操作回数を求めてください。変換が不可能な場合は -1 を返します。 入力例 たとえば、次のような盤面が与えられたとします。 この場合の出力は 2 になります。 変換の手順 第1操作: まず2列目と3列目を入れ替えます。すると盤面は次のようになります。 第2操作: 続いて2行目と3行目を入れ替えます。 これで盤面は完全なチェス盤パタ

  20. C++でK番目に小さい素数の分数を求めるアルゴリズム|優先度付きキューによる解法

    ソート済みのリストがあり、その中には 1 と複数の素数が含まれているとします。リスト内のすべての組合せ p < q について分数 p/q を考え、そのうち k 番目に小さい分数を求めます。答えは配列として返却し、ans[0] には分子 p、ans[1] には分母 q を格納します。 たとえば、入力が [1, 3, 5, 7]、k = 2 の場合を考えてみましょう。生成される分数は 1/3、1/5、1/7、3/5、3/7、5/7 の6つで、2番目に小さいのは 1/5 です。したがって答えは 1/5 となります。 解法のアプローチ この問題は優先度付きキュー(priority queue)を

Total 5990 -コンピューター  FirstPage PreviousPage NextPage LastPage CurrentPage:178/300  20-コンピューター/Page Goto:1 172 173 174 175 176 177 178 179 180 181 182 183 184