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

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_MAXint arr[row]int totalint firstint end を宣言します。

    • 外側のループで temp を0から column 未満まで回し、ループ内で配列要素をすべて0に初期化します。続いて temp_2temp から column 未満まで回す二重ループを構築し、その内部で i を0から row 未満まで回しながら arr[i] = arr[i] + matrix[i][temp_2] として各行の累積和を計算します。

    • total に関数 Algo_Kad(arr, &first, &end, row) の戻り値を代入します。

    • totalresult より小さい場合、resulttotal で更新します。

    • 最終的な result を出力します。

  • 関数 int Algo_Kad(int* arr, int* first, int* end, int max_size)(カダネのアルゴリズム)の内部では以下を行います。

    • 一時変数として int total = 0int result = INT_MAXint temp = 0、そして *end = -1 を宣言します。

    • ループで i を0から max_size 未満まで回し、total = total + arr[i] と累積していきます。

    • total が0より大きい場合は total を0に、tempi + 1 にリセットします。

    • そうでない場合(totalresult より小さい場合)、resulttotal に、*firsttemp に、*endi に更新します。

    • *end-1 と等しくなければ、result を返します。

    • すべて正の値だったケースに備え、resultarr[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

  1. 【C++】配列を互いに素な配列に変換するための最小挿入回数を求める方法

    問題の概要 今回は、与えられた配列を互いに素な配列(コプライム配列)に変換するために必要な最小の挿入回数を求める、興味深い問題を取り上げます。互いに素な配列とは、隣り合う任意の2つの要素の最大公約数(GCD)が必ず1になる配列のことです。この記事では、必要な挿入回数に加えて、変換後の配列そのものも出力します。 例として、{5, 10, 20} という配列を考えてみましょう。この配列は隣接要素同士のGCDが5や10となるため、互いに素な配列ではありません。しかし、5と10の間、そして10と20の間にそれぞれ「1」を挿入すれば、{5, 1, 10, 1, 20} となり、すべての隣接ペアのGCD

  2. C++の配列パズル:減算演算子を使わずに「自分以外の要素の合計」を求める方法

    今回は、配列に関する興味深い問題を紹介します。n個の要素を持つ配列が与えられ、それをもとに同じくn個の要素を持つ別の配列を作成します。ただし、新しい配列のi番目には、元の配列のi番目の要素を除いたすべての要素の合計を格納します。さらに重要な制約として、減算演算子(-)を使用してはいけないという条件が課されています。 問題のポイント もし減算が使えるのであれば、話は簡単です。まず全要素の合計を求めておき、そこからi番目の要素を引いた値を新しい配列のi番目に格納すればよいだけです。しかし、この問題では減算が禁止されているため、別のアプローチが必要になります。 そこで、各位置i(0〜n-1)について