【问题标题】:Find the largest basin size in a given matrix在给定矩阵中找到最大的盆地尺寸
【发布时间】:2014-06-20 22:41:12
【问题描述】:

问题:

这是一个面试问题。

一群农民有一些海拔数据,我们将帮助他们了解降雨如何流经他们的农田。

我们将土地表示为高度的二维数组,并使用以下模型,基于水流下山的想法:

如果一个小区的八个相邻小区都有更高的海拔,我们称这个小区为盆地;水收集在盆地中。

否则,水会流向海拔最低的相邻单元格。

直接或间接流入同一水槽的细胞被称为同一盆地的一部分。

下面是几个例子:

输入:

1 1 2
1 1 7
3 6 9

尺寸 4

9 9 9 8 7 7
8 8 7 7 7 8
8 8 8 7 7 7
8 8 8 9 9 9
8 8 8 7 7 7
4 4 5 5 5 5
5 5 5 6 6 7
5 5 5 8 8 6

8 号

9 9 9 8 8 8
8 8 8 7 7 7
7 7 7 7 7 7
8 8 8 8 9 9
5 5 5 5 6 3
5 5 5 3 3 3

9 号

突出显示的值形成最大尺寸的盆地。

所以问题是

将地图划分为盆地。特别是,给定海拔地图,您的代码应将地图划分为盆地并输出最大盆地的大小。 我们需要突出显示最大尺寸的盆地。

如果问题有这个假设

“如果一个cell不是sink,你可以假设它有一个唯一的最低邻居,并且这个邻居将低于cell”

那我可以想到这个解决方案

    Each array element is a node in a graph. Construct the graph adding edges between the nodes:
  1 If node A is the smallest among all of its own neighbors, don't add an edge (it's a sink)
  2 There is an edge between two neighbors A and B iff A is the smallest of all neighbors of B.
  3 Finally traverse the graph using BFS or DFS and count the elements in the connected components.

到目前为止,我已经实现了算法的第三部分

#include<iostream>
#include<vector>
#include<string.h>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int cv[1000]; // array stores number of nodes in each connected components
int main()
{
queue<int>q;
bool visited[100000];

int t,i,j,x,y,cvindex=0;
int n,e;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&e);
vector< vector<int> >G(n);
memset(visited,0,sizeof(visited));

for(i=0;i<e;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}

int ans=0;
for(i=0;i<n;i++)
{
if(!visited[i]) 
{
q.push(i);
visited[i]=1;
cv[cvindex]++;

while(!q.empty())
{
int p=q.front();
q.pop();
for(j=0;j<G[p].size();j++)
{
if(!visited[G[p][j]])
{
visited[G[p][j]]=1;
q.push(G[p][j]);
cv[cvindex]++;
}
}
}
ans++;
cvindex++;
}
}
printf("%d\n",ans);
sort(cv,cv+cvindex);
for(int zz=0;zz<cvindex;zz++)
printf("%d ",cv[zz]);
}
}   

时间复杂度 O(n*m)

但是如何在没有假设的情况下解决上述问题? 我想要几乎相似的方法,稍作修改。

欢迎使用其他算法。

而且在时间复杂度方面是否存在更好的算法?

【问题讨论】:

  • 一个盆地怎么有任何尺寸 > 1 如果需要它有八个更高的邻居
  • 我不明白你想问什么?是的,一个节点可以有 8 个相邻节点。
  • @Ben 指的是:“如果一个小区的八个相邻小区都有更高的海拔,我们称这个小区为盆地”。鉴于该定义,盆地的大小始终为 1。
  • @IInspectable,不一定:它描述了一种可能的情况,而不是全部。在那一行中没有说 8 个更高的节点是必需的。
  • @Ben: 没必要,你可以查看示例 2 和示例 3,其中盆地没有尺寸 1

标签: c++ arrays algorithm graph


【解决方案1】:

这是我的工作代码。我还评论了我的每一步,以供您理解。如果您仍然找到了一些帮助,您可以提出来。

算法

  1. 根据高度确定第一家商店的索引。
  2. 然后从最小高度迭代到最大高度。
  3. 如果当前索引尚未访问,则将其设为盆地表面(可以收集水的地方),并将所有高度大于此的邻居设为非盆地表面。
  4. 重复第 3 步,直到访问完所有索引。
  5. 然后在 decaring 每个索引的状态之后。我们需要找到最大的盆地表面。我们可以使用 DFS 找到。

时间复杂度:O(ROWS*COLUMNS)

#include<iostream>
#include<vector>
#include<string.h>
#include<climits>

#define BASIN 1
#define NOT_BASIN 2
#define NOT_DEFINED_YET 3

#define ROW 1000
#define COLUMN 1000
#define MAXIMUM_HEIGHT_POSSIBLE 1000

using namespace std;

int heights[ROW][COLUMN];  // It stores the height
int maximumBasin[ROW][COLUMN]; // It stores the state of each index, Total 3 states possible, ( BASIN, NOT_BASIN, NOT_DEFINED_YET )
bool alreadyVisited[ROW][COLUMN]; // True, if currect index visited, otherwise false.
vector< pair<int, int> > heightsCoordinates[MAXIMUM_HEIGHT_POSSIBLE]; // It stores all the indexs of given height.
int N, M, maxHeightPossible;

int dx[] = {0, 1, 1, 1, 0, -1, -1, -1};
int dy[] = {1, 1, 0, -1, -1, -1, 0, 1};

bool isValidLocation(int x, int y) {
    if(x < 0 || x > M || y < 0 || y > N || alreadyVisited[x][y] == true) return false;
    return true;
}

void DFS_FOR_MARKING_WITH_GIVEN_VALUE(int value, int x, int y) {
    maximumBasin[x][y] = value;
    alreadyVisited[x][y] = true;
    for(int i = 0; i < 8; i++) if( isValidLocation(x + dx[i], y + dy[i]) && heights[x + dx[i]][y + dy[i]] >= heights[x][y] ) DFS_FOR_MARKING_WITH_GIVEN_VALUE(value, x + dx[i], y + dy[i]);
}

void DFS_FOR_COUNTING_BASINS_TOGETHER(int &cnt, int x, int y) {
    cnt++;
    alreadyVisited[x][y] = true;
    for(int i = 0; i < 8; i++) if( isValidLocation(x+dx[i], y+dy[i]) && maximumBasin[x + dx[i]][y + dy[i]] ==  BASIN ) DFS_FOR_COUNTING_BASINS_TOGETHER(cnt, x + dx[i], y + dy[i]);
}

void printBasin() {
    for(int i = 0; i < M; i++) {
        for(int j = 0; j < N; j++) cout << maximumBasin[i][j] << "  ";
        cout << endl;
    }
}

main() {

    cin >> M >> N >> maxHeightPossible;
    int x, y;
    int maximumCounts = INT_MIN;
    int cntTemp = 0;

    /**
     Take input and set NOT_DEFINED_YET for maximumBasin.
    **/
    for(int i = 0; i < M; i++) {
        for(int j = 0; j < N; j++) {
             cin >> heights[i][j];
             maximumBasin[i][j] = NOT_DEFINED_YET;
             heightsCoordinates[ heights[i][j] ].push_back(pair<int, int>(i, j));
        }
    }

    /**
    Iterate from smallest to largest height.
    If current index is  "NOT_DEFINED_YET" (means it is the candidate index where water can collect).  Water will come here from all neighbourhood whose height is greater than this.
    For that I call DFS_FOR_MARKING_WITH_GIVEN_VALUE function.
    **/
    for( int i = 0; i <= maxHeightPossible; i++ ){
        if(heightsCoordinates[i].size() == 0) continue;
        for(int j = 0; j < heightsCoordinates[i].size(); j++) {
            x = heightsCoordinates[i][j].first;
            y = heightsCoordinates[i][j].second;
            if( maximumBasin[x][y] == NOT_DEFINED_YET ) {
                maximumBasin[x][y] = BASIN;
                alreadyVisited[x][y] = true;
                for(int k = 0; k < 8; k++) {
                    if( isValidLocation( x + dx[k], y + dy[k] ) ) {
                        if ( heights[x + dx[k]][ y + dy[k]] > heights[x][y] ) {
                            DFS_FOR_MARKING_WITH_GIVEN_VALUE(NOT_BASIN, x + dx[k], y + dy[k]);
                        }
                    }
                }
            }
            else {
                // If  it is set by BASIN or NOT_BASIN, Shows already processed before.
            }
        }
    }

    //printBasin();

    memset(alreadyVisited, 0, sizeof(alreadyVisited));

    /**
        It simply counts basins which are together.
    **/
    for(int i = 0; i < M; i++) {
        for(int j = 0; j < N; j++) {
            if( alreadyVisited[i][j] == false && maximumBasin[i][j] == BASIN) {
                DFS_FOR_COUNTING_BASINS_TOGETHER(cntTemp, i, j);
                //cout << cntTemp << endl;
                if(cntTemp > maximumCounts ) maximumCounts = cntTemp;
                cntTemp = 0;
            }
        }
    }

    /**
        This is our final Answer.
    **/
    cout << maximumCounts << endl;
    return 0;
}

【讨论】:

  • 谢谢,但如果你能写出你用过的伪代码/算法,我会很感激你的工作。答案与粘贴源代码无关。
  • @Prashant 我已经在代码中的 cmets 中解释了我的算法。为了您更好地理解,我更新了我的答案。
  • 你的算法错了 {9, 9, 9, 8, 7, 7}, {8, 8, 7, 7, 7, 8}, {8, 8, 8, 7, 7 , 7}, {8, 8, 8, 9, 9, 9}, {8, 8, 8, 7, 7, 7}, {4, 4, 5, 5, 5, 5}, {5, 5 , 5, 6, 6, 7}, {5, 5, 5, 8, 8, 6} 给出答案 false false false false true true true false true true true false true false false true true true true true false false false false false false false false false true true false true true false false false false false false true true true false false true where true 是盆地,false 不是
【解决方案2】:

将高程图构建为一个图形,其中二维数组的每个元素都是一个节点。此外,如果节点 u 的高程 >= 节点 v 的高程,则从节点 u 到节点 v 有一条有向边。构造此图的 SCC 并选择最大的组件。那将是您正在寻找的盆地。

【讨论】:

  • 所以对于第一个例子,我们将有 26 条边??你是这么说的吗?
  • :这种方法的复杂性是多少?
  • @Prashant 找到 SCC 的复杂性与执行 DFS 的顺序相同,即 O(E),其中 E 是图中的边数。对于此图,E = O(mn)。
【解决方案3】:

我认为分水岭是您正在寻找的算法。它主要用于图像分割,但它基于在灰度图像中寻找盆地,所以我认为适用于您的问题。

【讨论】:

    【解决方案4】:

    算法

    1- 根据高度在优先队列中插入所有元素(最小堆) 2-从队列中逐个删除元素,直到队列为空,并将所有高度较大的邻居标记为非盆地。(使用深度优先遍历进一步将高度大于等于当前邻居的邻居标记为非盆地并继续删除元素从队列中) 当队列为空时,所有非盆地都被标记为非盆地

    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    /**
     * Created by dheeraj on 12/16/14.
     */
    public class FindingBasin {
        int[][] matrix;
        int rows;
        int cols;
    
        PriorityQueue<RowColHeight> rowColHeightPriorityQueue;
    
        private static class RowColHeight {
            int row;
            int col;
            int height;
    
            public RowColHeight(int row, int col, int height) {
                this.row = row;
                this.col = col;
                this.height = height;
            }
    
            @Override
            public boolean equals(Object obj) {
                RowColHeight obj1 = (RowColHeight) obj;
                if(obj1.row == this.row && obj1.col == this.col){
                    return true;
                }else{
                    return false;
                }
            }
    
    
        }
    
        public FindingBasin(int[][] matrix) {
            this.matrix = matrix;
            this.rows = matrix.length;
            this.cols = matrix[0].length;
        }
    
        public void findBasin() {
            rowColHeightPriorityQueue = new PriorityQueue<RowColHeight>(rows * cols, new Comparator<RowColHeight>() {
                @Override
                public int compare(RowColHeight o1, RowColHeight o2) {
                    return o1.height - o2.height;
                }
            });
    
            // basin matrix -> true basin , false non basin
            boolean[][] basinMatrix = new boolean[rows][cols];
            boolean[][] visitedMatrix = new boolean[rows][cols];
            // sort matrix data on the basis of heights
            for (int x = 0; x < rows; x++) {
                for (int y = 0; y < cols; y++) {
                    rowColHeightPriorityQueue.add(new RowColHeight(x, y, matrix[x][y]));
                    basinMatrix[x][y] = true;
                    visitedMatrix[x][y] = false;
                }
            }
    
            RowColHeight rowColHeight;
    
            while (!rowColHeightPriorityQueue.isEmpty()) {
                //find all non basins
                rowColHeight = rowColHeightPriorityQueue.remove();
    
                for (int x = Math.max(0, rowColHeight.row - 1); x < Math.min(rows, rowColHeight.row + 2); x++) {
                    for (int y = Math.max(0, rowColHeight.col - 1); y < Math.min(cols, rowColHeight.col + 2); y++) {
                        if (x == rowColHeight.row && y == rowColHeight.col) {
                            continue;
                        }
    
                        if (visitedMatrix[x][y]) {
                            continue;
                        } else {
                            visitedMatrix[x][y] = true;
                        }
    
                        if (matrix[x][y] > rowColHeight.height) {
                            basinMatrix[x][y] = false;
                            //matrix[x][y] is non basin so all its neighbours >= it are also non basins
                            markALlNonBasins(rowColHeightPriorityQueue,visitedMatrix,basinMatrix,x,y);
                        }
                    }
                }
            }
            for (int x = 0; x < rows; x++) {
                for (int y = 0; y < cols; y++) {
                    System.out.print(basinMatrix[x][y] + " ");
                }
                System.out.println();
            }
        }
    
        private void markALlNonBasins(PriorityQueue<RowColHeight> rowColHeightPriorityQueue,boolean[][] visitedMatrix,boolean[][] basinMatrix,int row,int column) {
    
            for (int x = Math.max(0,row - 1); x < Math.min(rows,row + 2); x++) {
                for (int y = Math.max(0,column - 1); y < Math.min(cols,column + 2); y++) {
                    if (x == row && y == column) {
                        continue;
                    }
    
                    if(visitedMatrix[x][y]){
                        continue;
                    }
    
                    if(matrix[x][y] >= matrix[row][column]){
                        visitedMatrix[x][y] = true;
                        basinMatrix[x][y] =false;
                        rowColHeightPriorityQueue.remove(new RowColHeight(x,y,matrix[x][y]));
                        markALlNonBasins(rowColHeightPriorityQueue,visitedMatrix,basinMatrix,x,y);
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            int[][] matrix = {
                    {9, 9, 9, 8, 7, 7},
                    {8, 8, 7, 7, 7, 8},
                    {8, 8, 8, 7, 7, 7},
                    {8, 8, 8, 9, 9, 9},
                    {8, 8, 8, 7, 7, 7},
                    {4, 4, 5, 5, 5, 5},
                    {5, 5, 5, 6, 6, 7},
                    {5, 5, 5, 8, 8, 6}
            };
    
            FindingBasin findingBasin = new FindingBasin(matrix);
            findingBasin.findBasin();
    
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-22
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      • 2021-12-11
      • 2014-03-13
      • 2013-07-18
      • 1970-01-01
      相关资源
      最近更新 更多