Как найти седловой элемент матрицы

Седловой элемент матрицы A=(a_{{i,j}})_{{i=1,j=1}}^{{m,n}} — элемент матрицы a_{{k,l}}, удовлетворяющий условиям {displaystyle a_{k,l}=max _{1leq ileq m}a_{i,l}=min _{1leq jleq n}a_{k,j}}, то есть элемент матрицы, который одновременно является минимальным элементом в соответствующей строке матрицы и максимальным элементом в соответствующем столбце матрицы. Из определения следует, что a_{{k,l}}=max _{{1leq ileq m}} min _{{1leq jleq n}}a_{{i,j}}=min _{{1leq jleq n}} max _{{1leq ileq m}}a_{{i,j}}. Более того, для матрицы существует седловой элемент тогда и только тогда, когда {displaystyle max _{1leq ileq m} min _{1leq jleq n}a_{i,j}=min _{1leq jleq n} max _{1leq ileq m}a_{i,j}}.

Аналогичным образом можно определить понятие седловая точка для любой функции от двух переменных: точка {displaystyle (x^{*},y^{*})} является седловой точкой функции f, определённой на декартовом произведении Xtimes Y, если

{displaystyle f(x^{*},y^{*})=max _{xin X}f(x,y^{*})=min _{yin Y}f(x^{*},y)}[1]

Примеры[править | править код]

Матрица

{begin{bmatrix}5&6&4&5\-2&5&3&7\8&7&-2&6\end{bmatrix}}

имеет 1 седловой элемент, равный 4, который расположен в первой строке в третьем столбце матрицы, так как он одновременно является минимальным элементом в соответствующей строке матрицы (в данном случае в первой строке матрицы) и максимальным элементом в соответствующем столбце матрицы (в данном случае в третьем столбце матрицы).

Матрица

{begin{bmatrix}2&3&5&2\2&4&6&2\-2&7&2&0\end{bmatrix}}

имеет 4 седловых элемента, равных 2, которые расположены в первой строке в первом столбце, в первой строке в четвёртом столбце, во второй строке в первом столбце, во второй строке в четвёртом столбце матрицы, соответственно.

Данный пример показывает, что матрица может иметь несколько (более одной) седловых точек.

Тем не менее, если матрица имеет несколько седловых точек, то все их значения равны.

Так, в матрице, все элементы которой равны друг другу, все элементы являются седловыми точками.

Матрица

{begin{bmatrix}3&2&1\1&3&4\end{bmatrix}}

не имеет седловой точки.

Применение[править | править код]

Вышеприведенное использование термина «седловая точка» имеет особое значение в теории игр. Так, например, в играх с нулевой суммой седловая точка платёжной матрицы является равновесием Нэша.

Примечания[править | править код]

  1. Седловая точка (в теории игр) — статья из Математической энциклопедии. В. Л. Крепс

C++: как найти все седловые точки в матрице

Понятие седловой точки матрицы широко применяется в теории игр и кое-где ещё.
Седловой точкой называется
элемент матрицы, который одновременно является минимальным элементом в соответствующей строке матрицы и максимальным элементом в соответствующем столбце матрицы, или, что то же самое, элемент матрицы, который одновременно является максимальным элементом в соответствующем столбце матрицы и минимальным элементом в строке.

Следует учесть, что
если матрица имеет несколько седловых точек, то все их значения равны.
Если все числа в матрице различны, то и седловой точки не более одной.
Если все числа в матрице одинаковы, число седловых точек равно числу элементов.

Сначала листинг с “элементарно-переборным” подходом.

Функция int saddle (int n,int m,int **a,int is,int js) проверяет, является ли элемент
a[is][js] матрицы a размерностью n*m её седловой точкой. Вернёт 1 (да) или 0 (нет).

Функция int *saddle_points (int n, int m, int **a, int &k) находит все седловые точки матрицы. Использует первую функцию. Возвращает количество седловых точек через параметр-ссылку k, а основная возвращаемая величина – вектор размерностью 2*k, содержащий координаты строк и столбцов всех седловых точек матрицы. Например если в матрице 2 седловых точки, находящихся в позициях (0,1) и (3,2), вектор будет состоять из чисел (0,1,3,2) (нумерация с нуля).

В main интересен также способ переписать вектор из (n*m) элементов построчно в матрицу размерности n*m:

//Если число элементов items = n*m, код корректно перепишет вектор в матрицу (по строкам)
for (i=0; i<n*m; i++) a[i/m][i%m]=items[i];

Проверьте, для матрицы размерностью 8*2 должен получиться порядок

0 1
2 3
4 5
6 7
8 9
10 11
12 13
14 15

а для 4*4 – как у нас,

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Это нужно для того, что мне захотелось передавать в функции параметр типа int **a, а при подстановке фактического параметра-адреса матрицы

int a[n][m];

во многих компиляторах я рисковал бы получить ошибку вроде

Cannot convert 'int [4] *' to 'int * *'

Код же из листинга должен работать независимо от настроек приведения типов.

#include <stdlib.h>
#include <stdio.h>

int saddle (int n,int m,int **a,int is,int js) {
 int i,j,min,max;
 min=a[is][0];
 for (j=0; j<m; j++) if (a[is][j]<min) min=a[is][j];
 max=a[0][js];
 for (i=0; i<n; i++) if (a[i][js]>max) max=a[i][js];
 return (a[is][js]==min && a[is][js]==max ? 1 : 0);
}

int *saddle_points (int n, int m, int **a, int &k) {
 int i,j;
 k=0;
 for (i=0; i<n; i++)
 for (j=0; j<m; j++) {
  if (saddle(n,m,a,i,j)) k++;
 }
 if (k==0) return NULL;
 int *s = new int [k*2];
 if (s==NULL) return NULL;
 int l=0;
 for (i=0; i<n; i++)
 for (j=0; j<m; j++) {
  if (saddle(n,m,a,i,j)) { s[l++]=i; s[l++]=j; }
 }
 return s;
}

int main () {
 const int n=4,m=4;
 int **a;
 int items[] = {
  7,-1,-4,1,
  3,2,3,2,
  2,2,3,2,
  4,-3,7,-2
 };
 int i,j;
 a = new int * [n];
 for (i=0; i<n; i++) a[i] = new int [m];
 //Если число элементов items = n*m, код корректно перепишет вектор в матрицу (по строкам)
 for (i=0; i<n*m; i++) a[i/m][i%m]=items[i];

 printf ("nПолучена матрица:");
 for (i=0; i<n; i++) {
  printf ("n");
  for (j=0; j<m; j++) printf ("%d ",a[i][j]);
 }
 int k=0;
 int *s=saddle_points (n,m,a,k);
 if (k>0) {
  for (i=0; i<2*k; i+=2) {
   printf ("na[%d,%d]=%d",s[i],s[i+1],a[s[i]][s[i+1]]);
  }
 }
 else printf ("nНет седловых точек или не выделена память");
 printf ("nENTER");
 getchar();
 return 0;
}

Для поиска всех седловых точек в матрицах большой размерности не нужно рассматривать каждый элемент отдельно.

Рассмотрим более “культурный” алгоритм поиска всех седловых точек матрицы. Покажем его работу на примере.

Дана матрица:

7 -1 -4  1
4  2  3  2
2  2  3  2
4 -3  7 -2

Требуется найти все её седловые точки.

Соберём наименьшие значения по всем строкам, получим вектор A=(-4, 2, 2, -3).

Соберём наибольшие значения по всем столбцам, получим вектор B=(7, 2, 7, 2).

Проверка: максимум первого набора никогда не может быть больше минимума второго.

Если максимум первого набора меньше, чем минимум второго, то седловых точек нет.

Если максимум первого набора равен минимуму второго (в нашем случае число 2), мы нашли значение S седловой точки.

Теперь посмотрим, на каких позициях в векторах A и B находятся значения S.

При нумерации с единицы, в первом наборе это позиции 2 и 3, а во втором – позиции 2 и 4.

На произведении этих множеств располагаются все седловые точки. В нашем случае
{2, 3} * {2, 4} = { {2, 2}, {3, 2}, {2, 4}, {3, 4} } – координаты в матрице всех седловых точек, опять же, при нумерации с единицы.

Одна из возможных реализаций этого алгоритма:

#pragma hdrstop
#pragma argsused
#include <tchar.h>
/* в некоторых компиляторах нужно убрать 3 верхних строчки */
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <ctime>
 
 
int main ()
{
    const int strok = 4 , stolbcov = 4;
    int i,j,k,z, maxofmin,minofmax;
    int matr[strok][stolbcov] = {{7,-1,-4,1},{4,2,3,2},{2,2,3,2},{4,-3,7,-2}};
    int max[stolbcov], min[strok];
   /*   srand(time(0));
    for (i = 0; i < strok; i++)
        for (j = 0; j < stolbcov; j++)
            matr[i][j]=rand()%9+1;     */
    for (i = 0; i < strok; i++)
    {
        std::cout << "n";
        for (j = 0; j < stolbcov; j++)
        {
            std::cout<< std::setw(3)<<matr[i][j];
        }
    }
    std::cout << std::endl;
    j = 0;
    for (i = 0; i < strok; i++)
    {
        for (j = 0; j < stolbcov; j++)
        {
            min[i] = matr[i][j];
            if (min[i] > matr[i][j])
                min[i] = matr[i][j];
        }
    }
    j = 0;
    for (j = 0; j < stolbcov; j++)
    {
        i=0;
        max[j] = matr[i][j];
        for (i = 0; i < strok; i++)
            if (max[j] < matr[i][j])
                max[j] = matr[i][j];
 
    }
    maxofmin = min[0];
    for (i = 0; i < strok; i++)
        if (maxofmin < min[i])
            maxofmin = min[i];
    minofmax = max[0];
        for (i = 0; i < stolbcov; i++)
            if (minofmax > max[i])
                minofmax = max[i];
    if (minofmax > maxofmin)
        std::cout << "Sedlovix tochek net" << std::endl;
    else
        std::cout << "Sedlovie tochki = " <<std::endl;
    for (i = 0; i < strok; i++)
        if (min[i] == maxofmin)
            for (j = 0; j < stolbcov; j++)
                if (max[j] == minofmax)
                    std::cout << i << " " << j << std::endl;
    system("pause");
    return 0;
}

15.11.2013, 17:48 [34279 просмотров]


К этой статье пока нет комментариев, Ваш будет первым

Given a matrix of n x n size, the task is to find the saddle point of the matrix. A saddle point is an element of the matrix such that it is the minimum element in its row and the maximum in its column. 

Examples : 

Input: Mat[3][3] = { {1, 2, 3},
                  {4, 5, 6},
                  {7, 8, 9}}
Output: 7
7 is minimum in its row and maximum in its column.

Input: Mat[3][3] = {{1, 2, 3},
                    {4, 5, 6},
                    {10, 18, 4}}
Output: No saddle point

A simple solution is to traverse all matrix elements one by one and check if the element is Saddle Point or not.

An efficient solution is based on the below steps. 

Traverse all rows one by one and do the following for every row i.  

  1. Find the minimum element of the current row and store the column index of the minimum element.
  2. Check if the row minimum element is also maximum in its column. We use the stored column index here.
  3. If yes, then saddle point else continues till the end of the matrix.

Below is the implementation of the above steps.  

C++

#include <bits/stdc++.h>

using namespace std;

const int MAX = 100;

bool findSaddlePoint(int mat[MAX][MAX], int n)

{

    for (int i = 0; i < n; i++)

    {

        int min_row = mat[i][0], col_ind = 0;

        for (int j = 1; j < n; j++)

        {

            if (min_row > mat[i][j])

            {

                min_row = mat[i][j];

                col_ind = j;

            }

        }

        int k;

        for (k = 0; k < n; k++)

            if (min_row < mat[k][col_ind])

                break;

        if (k == n)

        {

           cout << "Value of Saddle Point " << min_row;

           return true;

        }

    }

    return false;

}

int main()

{

    int mat[MAX][MAX] = {{1, 2, 3},

                        {4, 5, 6},

                        {7, 8, 9}};

    int n = 3;

    if (findSaddlePoint(mat, n) == false)

       cout << "No Saddle Point ";

    return 0;

}

C

#include <stdio.h>

#include <stdbool.h>

#define MAX 100

bool findSaddlePoint(int mat[MAX][MAX], int n)

{

    for (int i = 0; i < n; i++)

    {

        int min_row = mat[i][0], col_ind = 0;

        for (int j = 1; j < n; j++)

        {

            if (min_row > mat[i][j])

            {

                min_row = mat[i][j];

                col_ind = j;

            }

        }

        int k;

        for (k = 0; k < n; k++)

            if (min_row < mat[k][col_ind])

                break;

        if (k == n)

        {

           printf("Value of Saddle Point %d",min_row);

           return true;

        }

    }

    return false;

}

int main()

{

    int mat[MAX][MAX] = {{1, 2, 3},

                        {4, 5, 6},

                        {7, 8, 9}};

    int n = 3;

    if (findSaddlePoint(mat, n) == false)

       printf("No Saddle Point ");

    return 0;

}

Java

class Test

{

    static boolean findSaddlePoint(int mat[][    ], int n)

    {

        for (int i = 0; i < n; i++)

        {

            int min_row = mat[i][0], col_ind = 0;

            for (int j = 1; j < n; j++)

            {

                if (min_row > mat[i][j])

                {

                    min_row = mat[i][j];

                    col_ind = j;

                }

            }

            int k;

            for (k = 0; k < n; k++)

                if (min_row < mat[k][col_ind])

                    break;

            if (k == n)

            {

               System.out.println("Value of Saddle Point " + min_row);

               return true;

            }

        }

        return false;

    }

    public static void main(String[] args)

    {

        int mat[][] = {{1, 2, 3},

                      {4, 5, 6},

                     {7, 8, 9}};

        int n = 3;

        if (findSaddlePoint(mat, n) == false)

            System.out.println("No Saddle Point ");

    }

}

Python3

def findSaddlePoint(mat, n):

    for i in range(n):

        min_row = mat[i][0];

        col_ind = 0;

        for j in range(1, n):

            if (min_row > mat[i][j]):

                min_row = mat[i][j];

                col_ind = j;

        k = 0;

        for k in range(n):

            if (min_row < mat[k][col_ind]):

                break;

            k += 1;

        if (k == n):

            print("Value of Saddle Point ",

                  min_row);

            return True;

    return False;

if __name__ == '__main__':

    mat = [[1, 2, 3],

           [4, 5, 6],

           [7, 8, 9]];

    n = 3;

    if (findSaddlePoint(mat, n) ==

        False):

        print("No Saddle Po");

C#

using System;

class GFG {

    static bool findSaddlePoint(int [,] mat,

                                int n)

    {

        for (int i = 0; i < n; i++)

        {

            int min_row = mat[i, 0], col_ind = 0;

            for (int j = 1; j < n; j++)

            {

                if (min_row > mat[i, j])

                {

                    min_row = mat[i, j];

                    col_ind = j;

                }

            }

            int k;

            for (k = 0; k < n; k++)

                if (min_row < mat[k, col_ind])

                    break;

            if (k == n)

            {

                Console.WriteLine("Value of Saddle Point "

                                                + min_row);

                return true;

            }

        }

        return false;

    }

    public static void Main()

    {

        int [,] mat = {{1, 2, 3},

                       {4, 5, 6},

                       {7, 8, 9}};

        int n = 3;

        if (findSaddlePoint(mat, n) == false)

            Console.WriteLine("No Saddle Point ");

    }

}

PHP

<?php

$MAX = 100;

function findSaddlePoint( $mat, $n)

{

    for ( $i = 0; $i < $n; $i++)

    {

        $min_row = $mat[$i][0];

        $col_ind = 0;

        for ( $j = 1; $j < $n; $j++)

        {

            if ($min_row > $mat[$i][$j])

            {

                $min_row = $mat[$i][$j];

                $col_ind = $j;

            }

        }

        $k;

        for ($k = 0; $k < $n; $k++)

            if ($min_row < $mat[$k][$col_ind])

                break;

        if ($k == $n)

        {

        echo "Value of Saddle Point " ,

                              $min_row;

        return true;

        }

    }

    return false;

}

$mat = array(array(1, 2, 3),

             array(4, 5, 6),

             array (7, 8, 9));

$n = 3;

if (findSaddlePoint($mat, $n) == false)

echo "No Saddle Point ";

?>

Javascript

<script>

function findSaddlePoint(mat, n)

{

        for (let i = 0; i < n; i++)

        {

            let min_row = mat[i][0], col_ind = 0;

            for (let j = 1; j < n; j++)

            {

                if (min_row > mat[i][j])

                {

                    min_row = mat[i][j];

                    col_ind = j;

                }

            }

            let k;

            for (k = 0; k < n; k++)

                if (min_row < mat[k][col_ind])

                    break;

            if (k == n)

            {

               document.write("Value of Saddle Point " + min_row+"<br>");

               return true;

            }

        }

        return false;

}

let mat = [[1, 2, 3],

                      [4, 5, 6],

                     [7, 8, 9]];

        let n = 3;

        if (findSaddlePoint(mat, n) == false)

            document.write("No Saddle Point ");

</script>

Output

Value of Saddle Point 7

Time Complexity: O(n*n)
Auxiliary Space: O(1)

Exercise : 
Can there be more than one Saddle Points in a Matrix?

This article is contributed by Sahil Chhabra(KILLER). If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Last Updated :
02 Aug, 2022

Like Article

Save Article

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
 
enum {N=4, M=5};
 
void printf_arr (int [][M], int, int);
void random_arr (int [][M], int, int);
int  max_in_col (int [][M], int, int, int);
int  min_in_row (int [][M], int, int, int);
void saddle_point (int [][M], int, int);
 
int main (void) {
    int a[N][M] = {
        {   2,  12,   6,   45,  77},
        {   2,   3,   1,   79, 105},
        {   2,  44,   3,   32,  21},
        {   0,  83,   0,   19,  -6}
    };
 
    int b[N][M] = { {0} };
    random_arr(b, N, M);
 
    puts("массив a:");
    printf_arr(a, N, M);
    saddle_point(a, N, M);
 
    puts("nмассив b:");
    printf_arr(b, N, M);
    saddle_point(b, N, M);
 
    return 0;
}
// -------------------------------------------------------------
void printf_arr (int a[][M], int rows, int columns) {
    for (int i=0; i<rows; i++, puts(""))
        for (int k=0; k<columns; k++)
            printf("% 4d", a[i][k]);
    puts("");
}
// -------------------------------------------------------------
void random_arr (int a[][M], int rows, int columns) {
    srand( (unsigned int)time(NULL)/2 );
    for (int i=0; i<rows; i++)
        for (int k=0; k<columns; k++)
            a[i][k] = rand() %101 - 50;
}
// -------------------------------------------------------------
int  max_in_col (int a[][M], int rows, int columns, int column) {
    int max = 0;
    for (int i=1; i<rows; i++)
        if (a[i][column] > a[max][column])
            max = i;
    return max;         // возвращает строку
}
// -------------------------------------------------------------
int  min_in_row (int a[][M], int rows, int columns, int row) {
    int max = 0;
    for (int k=1; k<columns; k++)
        if (a[row][k] < a[row][max])
            max = k;
    return max;         // возвращает столбец
}
// -------------------------------------------------------------
void saddle_point (int a[][M], int rows, int columns) {
    int i, k, min[N], max[M];
    for (i=0; i<rows; i++)
        min[i] = a[i][min_in_row(a, rows, columns, i)];
    for (k=0; k<columns; k++)
        max[k] = a[max_in_col(a, rows, columns, k)][k];
 
    int found = 0;
    for (i=0; i<rows; i++)
        for (k=0; k<columns; k++)
            if (a[i][k] == min[i] && a[i][k] == max[k]) {
                printf("%4d", a[i][k]);
                found++;
            }
 
    if (found < 1)
        puts("В массиве нет седловых точек!");
    else
        printf("nВыявлено %d седловые точки.n", found);
}
// -------------------------------------------------------------

Вариант решения с учетом возможных повторений минимумов и максимумов.
Не претендует на идеальный, памяти многовато ест. скорее всего можно оптимизировать.

Временная сложность O(MxN), Использование дополнительной памяти O(MxN)

Код на C#, но кроме двумерных массивов в данном фрагменте все идентично C++, адаптация не должна стать проблемой.

int m;//Количество столбцов
int n;//Количество строк
//читаем M и N
int[,] source = new int[m, n];//исходная матрица
int[,] finder = new int[m, n];//матрица поиска
//заполняем исходную матрицу любым способом
//заполняем матрицу поиска нулями
for (int j = 0; j < n; j++){
    //ищем минимум в строке
    int minInd = 0;
    for (int i = 1; i < m; i++)
        if (source[minInd,j]>source[i,j])
            minInd = i;
    //Отмечаем на матрице поиска все минимумы прибавляя 1
    for (int i = 0; i < m; i++)
        if (source[minInd, j] == source[i, j])
            finder[i, j]++;
}
//Повторяем все то же для максимумов столбцов
for (int i = 0; i < m; i++){
    int maxInd = 0;
    for (int j = 1; j < n; j++)
        if (source[i, maxInd] < source[i, j])
            maxInd = j;
    for (int j = 0; j < n; j++)
        if (source[i, maxInd] == source[i, j])
            finder[i, j]++;
}
int result = 0;
for (int j = 0; j < n; j++)
    for (int i = 1; i < m; i++)
        if (finder[i, j] == 2)//если минимум строки и максимум столбца 
            result++;         //совпали, ячейка матрицы поиска будет равна 2

//из result забираем количество найденных седловых элементов

Добавить комментарий