草庐IT

c++ - 在给定矩阵中找到最大的盆地大小

coder 2024-02-05 原文

问题:

这是一个面试问题。

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

我们将土地表示为一个二维的高度数组,并根据水流下坡的想法使用以下模型:

如果一个单元格的八个相邻单元格都具有较高的海拔高度,我们称这个单元格为盆地;水聚集在盆中。

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

直接或间接排入同一个汇的细胞被称为同一个盆地的一部分。

下面是几个例子:

输入:

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号

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

所以问题是

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

如果问题有这个假设

“如果一个单元格不是汇点,您可以假设它有一个唯一的最低邻居,并且这个邻居将低于该单元格”

然后我可以想到这个解决方案

    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. 首先根据高度存储索引。
  2. 然后从最小高度迭代到最大高度。
  3. 如果还没有访问过当前索引,则将其设为盆地表面(可以收集水的地方),并将所有高度大于此的邻居设为非盆地表面。
  4. 重复第 3 步,直到访问完所有索引。
  5. 然后在声明每个索引的状态之后。我们需要找到最大的盆地表面。我们可以使用 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;
}

关于c++ - 在给定矩阵中找到最大的盆地大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24336686/

有关c++ - 在给定矩阵中找到最大的盆地大小的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - capybara ::ElementNotFound:无法找到 xpath "/html" - 2

    我正在学习http://ruby.railstutorial.org/chapters/static-pages上的RubyonRails教程并遇到以下错误StaticPagesHomepageshouldhavethecontent'SampleApp'Failure/Error:page.shouldhave_content('SampleApp')Capybara::ElementNotFound:Unabletofindxpath"/html"#(eval):2:in`text'#./spec/requests/static_pages_spec.rb:7:in`(root)'

  4. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. HBase Region 简介和建议数量&大小 - 2

    Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile

  7. ruby - 如何找到调用当前方法的方法 - 2

    如何找到调用此方法的位置?defto_xml(options={})binding.pryoptions=options.to_hifoptions&&options.respond_to?(:to_h)serializable_hash(options).to_xml(options)end 最佳答案 键入caller。这将返回当前调用堆栈。文档:Kernel#caller.例子[0]%rspecspec10/16|===================================================62=====

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. ruby-on-rails - Ruby 中意外的大小写行为 - 2

    我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。

  10. ruby - 改变替换的大小写 - 2

    我有以下内容:text.gsub(/(lower)(upper)/,'\1\2')我可以将\2替换为大写吗?类似于:sed-e's/\(abc\)/\U\1/'这在Ruby中可行吗? 最佳答案 查看gsub文档:str.gsub(模式){|匹配|block}→new_str在block形式中,当前匹配字符串作为参数传入,$1、$2、$`、$&、$'等变量将被适当设置。block返回的值将替换为每次调用的匹配项。"alowerupperb".gsub(/(lower)(upper)/){|s|$1+""+$2.upcase}

随机推荐