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

C++で方程式 f(x, y) = z を満たす正の整数解をすべて求める方法


問題の概要

2つの引数 (x, y) を受け取る関数 f があると仮定します。この関数は単調増加関数であり、次の性質を持ちます。

  • f(x, y) < f(x + 1, y)
  • f(x, y) < f(x, y + 1)

つまり、x または y の値を大きくすると、必ず f の戻り値も大きくなります。このとき、入力として与えられた z に対して、f(x, y) = z を満たす正の整数 x、y の組み合わせをすべて求めるのが本記事の目的です。

解き方:全探索アプローチ

ここでは、最も理解しやすい全探索(ブルートフォース)の手法を採用します。変数 i を 1〜1000、変数 j を 1〜1000 の範囲で二重ループさせ、すべての組み合わせ (i, j) について f(i, j) と z が一致するかどうかを確認します。条件を満たすペアが見つかったら、それを結果リストに追加していきます。

サンプルコードの CustomFunction クラスには、関数の種類を表す id を渡します。

  • id = 1:加算(f(x, y) = x + y)
  • id = 2:乗算(f(x, y) = x × y)

このアルゴリズムの計算量は O(1000 × 1000) = O(n²) です。なお、関数が単調増加であるという性質を利用すれば、双方向ポインタ(two pointers)テクニックによって O(n) まで高速化できる点にも触れておきます。

実装例

以下は C++ による実装例です。実際の動作を確認してみましょう。

#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<vector<int> > v){
   cout << "[";
      for(int i = 0; i<v.size(); i++){
         cout << "[";
            for(int j = 0; j <v[i].size(); j++){
               cout << v[i][j] << ", ";
            }
            cout << "],";
      }
      cout << "]"<<endl;
}
class CustomFunction {
   int id;
   public:
   CustomFunction(int id){
      this->id = id;
   }
   int f(int x, int y){
      if(id == 1)
         return y + x;
      else if(id == 2)
         return y * x;
      return 0;
   }
};
class Solution {
   public:
   vector<vector<int>> findSolution(CustomFunction& c, int z) {
      vector  < vector <int > > ans;
      for(int i = 1; i <= 1000; i++ ){
         for(int j = 1; j <= 1000; j++){
            if(c.f(i,j) == z){
               vector <int> t;
               t.push_back(i);
               t.push_back(j);
               ans.push_back(t);
            }
         }
      }
      return ans;
   }
};
main(){
   Solution ob;
   CustomFunction c(1);
   print_vector(ob.findSolution(c, 7));
}

入力

1
7

出力

[[1, 6],[2, 5],[3, 4],[4, 3],[5, 2],[6, 1]]

出力の解説

今回の入力では id = 1(加算)が指定されているため、f(x, y) = x + y として計算されます。z = 7 なので、「和が 7 になる正の整数のペア」、すなわち (1, 6)、(2, 5)、(3, 4)、(4, 3)、(5, 2)、(6, 1) の 6 組が出力されています。id = 2(乗算)を指定すれば、積が z になるペアを同様の手順で求められます。

  1. C++で指定された差分を持つペアを見つける方法

    はじめに 配列 A に n 個の異なる要素が格納されているとします。この配列から、2つの要素 x と y の差が指定された値 d と一致するようなペア (x, y) をすべて見つける必要があります。 例として、配列が A = [10, 15, 26, 30, 40, 70]、指定された差分が 30 である場合を考えます。このとき、該当するペアは (10, 40) と (40, 70) です。 解法:ツーポインタ法 この問題は、配列が昇順にソートされていることを前提とすれば、ツーポインタ(二重インデックス)法を使って効率的に解くことができます。まず、1つ目のポインタ「i」を先頭の要素に、2つ目の

  2. C++で配列要素の階乗の最大公約数(GCD)を求める方法

    N個の要素を持つ配列Aが与えられたとき、配列内のすべての要素の階乗の最大公約数(GCD)を求めることを考えます。例えば、配列の要素が {3, 4, 8, 6} の場合、各要素の階乗は 3! = 6、4! = 24、8! = 40320、6! = 720 となり、これらのGCDは 6 になります。解法のポイントここで重要な数学的な性質があります。2つの数のGCDとは、両方の数を割り切る最大の数のことです。階乗の場合、小さい数の階乗は必ず大きい数の階乗を割り切ることができます。つまり、2つの階乗のGCDは、小さい方の数の階乗そのものになります。例えば、3! と 5! のGCDを考えると、3! =