C++で2次元配列における最小合計部分行列を求めるアルゴリズム
問題概要
整数要素で構成される2次元配列(行列)が与えられたとき、その中から部分行列を取り出し、合計が最小となる値を求めるのが本記事のテーマです。
それでは、具体的な入出力シナリオを見ていきましょう。
入出力例1
入力 −
int matrix[size][size] = { {2, 3, -1, 5}, {-2, 9, -1, 6}, {5, 6, 9, -9}, {-6, 1, 1, 1} }出力 − 与えられた2次元配列における最小合計部分行列は: -9
説明 − 4行4列(サイズ4x4)の2次元配列が与えられています。この中から合計が最小となる部分行列を探すと、答えは -9 になります。
入出力例2
入力 −
int matrix[row][column] = { {4, 1, 3}, {-1, -1, -1}, {6, 2, 3} }出力 − 与えられた2次元配列における最小合計部分行列は: -3
説明 − 3行3列(サイズ3x3)の2次元配列が与えられています。2行目全体を選んだ「1行3列」の部分行列により、最小合計 -3 が達成されます。
プログラムで使用するアプローチ
整数型の2次元配列を入力として受け取り、処理用の関数
Minimum_Matrix(matrix)にデータを渡します。関数
Minimum_Matrix(matrix)の内部では以下を行います。一時変数として
int result = INT_MAX、int arr[row]、int total、int first、int endを宣言します。外側のループで
tempを0からcolumn未満まで回し、ループ内で配列要素をすべて0に初期化します。続いてtemp_2をtempからcolumn未満まで回す二重ループを構築し、その内部でiを0からrow未満まで回しながらarr[i] = arr[i] + matrix[i][temp_2]として各行の累積和を計算します。totalに関数Algo_Kad(arr, &first, &end, row)の戻り値を代入します。totalがresultより小さい場合、resultをtotalで更新します。最終的な
resultを出力します。
関数
int Algo_Kad(int* arr, int* first, int* end, int max_size)(カダネのアルゴリズム)の内部では以下を行います。一時変数として
int total = 0、int result = INT_MAX、int temp = 0、そして*end = -1を宣言します。ループで
iを0からmax_size未満まで回し、total = total + arr[i]と累積していきます。totalが0より大きい場合はtotalを0に、tempをi + 1にリセットします。そうでない場合(
totalがresultより小さい場合)、resultをtotalに、*firstをtempに、*endをiに更新します。*endが-1と等しくなければ、resultを返します。すべて正の値だったケースに備え、
resultをarr[0]に、*firstを0に、*endを0に設定します。ループで
iを1からmax_size未満まで回し、arr[i]がresultより小さければresult、*first、*endをそれぞれ更新します。resultを返します。
サンプルコード
#include <bits/stdc++.h>
using namespace std;
#define row 4
#define column 4
int Algo_Kad(int* arr, int* first, int* end, int max_size)
{
int total = 0;
int result = INT_MAX;
int temp = 0;
*end = -1;
for(int i = 0; i < max_size; ++i)
{
total = total + arr[i];
if(total > 0)
{
total = 0;
temp = i + 1;
}
else if(total < result)
{
result = total;
*first = temp;
*end = i;
}
}
if(*end != -1)
{
return result;
}
result = arr[0];
*first = 0;
*end = 0;
for(int i = 1; i < max_size; i++)
{
if(arr[i] < result)
{
result = arr[i];
*first = i;
*end = i;
}
}
return result;
}
void Minimum_Matrix(int matrix[][column])
{
int result = INT_MAX;
int arr[row];
int total;
int first;
int end;
for(int temp = 0; temp < column; ++temp)
{
memset(arr, 0, sizeof(arr));
for(int temp_2 = temp; temp_2 < column; ++temp_2)
{
for(int i = 0; i < row; ++i)
{
arr[i] = arr[i] + matrix[i][temp_2];
}
total = Algo_Kad(arr, &first, &end, row);
if(total < result)
{
result = total;
}
}
}
cout<<"Minimum sum submatrix in a given 2D array is: "<<result;
}
int main()
{
int matrix[row][column] = {{2, 3, -1, 5},
{-2, 9, -1, 6},
{ 5, 6, 9, -9},
{ -6, 1, 1, 1} };
Minimum_Matrix(matrix);
return 0;
}実行結果
上記のコードを実行すると、以下の出力が得られます。
Minimum sum submatrix in a given 2D array is: -9
-
【C++】配列を互いに素な配列に変換するための最小挿入回数を求める方法
問題の概要 今回は、与えられた配列を互いに素な配列(コプライム配列)に変換するために必要な最小の挿入回数を求める、興味深い問題を取り上げます。互いに素な配列とは、隣り合う任意の2つの要素の最大公約数(GCD)が必ず1になる配列のことです。この記事では、必要な挿入回数に加えて、変換後の配列そのものも出力します。 例として、{5, 10, 20} という配列を考えてみましょう。この配列は隣接要素同士のGCDが5や10となるため、互いに素な配列ではありません。しかし、5と10の間、そして10と20の間にそれぞれ「1」を挿入すれば、{5, 1, 10, 1, 20} となり、すべての隣接ペアのGCD
-
C++の配列パズル:減算演算子を使わずに「自分以外の要素の合計」を求める方法
今回は、配列に関する興味深い問題を紹介します。n個の要素を持つ配列が与えられ、それをもとに同じくn個の要素を持つ別の配列を作成します。ただし、新しい配列のi番目には、元の配列のi番目の要素を除いたすべての要素の合計を格納します。さらに重要な制約として、減算演算子(-)を使用してはいけないという条件が課されています。 問題のポイント もし減算が使えるのであれば、話は簡単です。まず全要素の合計を求めておき、そこからi番目の要素を引いた値を新しい配列のi番目に格納すればよいだけです。しかし、この問題では減算が禁止されているため、別のアプローチが必要になります。 そこで、各位置i(0〜n-1)について