在知道墙壁的位置的同时计算房间

时间:2016-06-16 19:20:50

标签: c++ algorithm variable-assignment c++builder

这个问题是关于C ++ builder 6的代码。赏金对标准C ++算法感兴趣,以便在给定标准化输入的情况下解决问题(有关详细信息,请参阅this。) < / p>

The castle

txt文件,它也代表我在数组中拥有的数据:

  

1101 0110 1101 0110 1100 0101 0110
  1110 1001 0110 1011 1010 1111 1010
  1000 0101 0011 1110 1011 1110 1010
  1011 1101 0101 0001 0101 0011 1011

txt的说明:
来自txt文件的数字是房间墙壁的4位表示,其中一个位表示墙。壁位按顺时针顺序开始,最重要的位是西墙。例如, 1101 代表一个房间:

  • 最重要位置的设定位表示西墙
  • 下一个最重要位置的设置位表示北方的墙
  • 未设置的位表示没有东墙
  • 最低位置的设定位表示南方的墙

假设:

  1. 房间的外墙总是有一面墙
  2. 内墙将始终在两个房间中表达(在示例中,因为(1,1)的房间是 1101 它包含一个南墙,房间在(1,2) 1110必须包含一堵北墙
  3. 永远不会超过numeric_limits<int>::max()个房间
  4. was asked to post my code所以这就是:
    我试图解决这个问题,但是我得到EAAccessviolation可以有人告诉我我做错了什么吗?

      int rn=0,z=0, global=0,coord[15],c[411],b1[411];
    
    void peruse ( int i, int j,int* bb)
    {
    bool top=false,bottom=false,right=false,left=false;
    //truth checks
    
    if (bb[i*m+j]<1000)  left=true;
    
    if (bb[i*m+j]<100)   top=true; else if (bb[i*m+j]-1000<100)   top=true;
    
    if (bb[i*m+j]<10)    right=true; else
    if ( (bb[i*m+j]-100<10) || (bb[i*m+j]-1000<10) || (bb[i*m+j]-100<10) ) right=true;
    
    if (bb[i*m+j]<1)   bottom=true; else
    if ( (bb[i*m+j]-10<1) || (bb[i*m+j]-100<1) || (bb[i*m+j]-1000<1) ||(bb[i*m+j]-100<1))
    bottom=true;
    //marc
    
    if  (left)
    {
    c[i*m+j]=c[i*m+j]+1000; // EAaccessViolation i dont know why.....
    peruse(i,j-1,c);
    }
    if (top)
    {
    c[i*m+j]=c[i*m+j]+100;
    peruse(i-1,j,c);
    }
    if (right)
    {
    c[i*m+j]=c[i*m+j]+10;
    peruse(i,j+1,c);
    }
    if (bottom)
    {
    c[i*m+j]=c[i*m+j]+1;
    peruse(i+1,i,c);
    }
     if ( !(left) && !(top) && !(right) && !(bottom) )
     {
      bb[411]++;
    
    
    
     }
    }
    
    
    void __fastcall TForm1::Button7Click(TObject *Sender)
    {
    b1[411]=0;
    
     for(int i=0;i<n;i++)
        for (int j=0;j<m;j++)
              {
               b1[i*m+j]=b[i][j];
               c[i*m+j]=b[i][j];
              }
      peruse (1,1,b1);
    
     ShowMessage("Nr. "+IntToStr(b1[411]) );
    }
    

5 个答案:

答案 0 :(得分:11)

这是在图表中查找connected components总数的典型问题。

让我通过关注以下几点来帮助您想象这个类比,请记住我们在这里处理undirected graphs

1 。在图形中,如果它们之间存在边缘,我们有各种顶点,并且两个顶点被认为彼此相邻。 就像你的城堡,如果一个细胞可以通往另一个细胞,那么两个细胞彼此相邻。

<强> 2 即可。在图中,如果两个顶点之间存在使用边的路径,则我们有两个顶点属于同一个连通组件。 就像你的城堡,其中两个单元格属于同一个房间号码,如果一个单元格可以通过遵循单元格的路径而导致另一个单元格。

第3 即可。在图形中,我们连接了组件,这样连接的组件由顶点组成,这样连接组件的每两个顶点之间都有一条路径。就像你的城堡我们有房间一样,每两个单元格同一个房间的细胞之间有一条细胞通道。

现在,如果您仍然想知道如何构建图表,那么很容易。

顶点的数量为NxM,对于大小为N行且M列的城堡),等于单元格数。

只需按顺序对单元格进行编号,如果两个单元格相邻,则cell a(meaning vertex a)cell b(vertex b)之间会有一条边。

现在可以通过在您构建的图表上应用bfs或dfs算法轻松计算房间总数。

该算法在我提供的第一个链接中描述。

答案 1 :(得分:6)

老实说,我真的很想尝试解决这个问题。所以我要说你在这方面做出了勇敢的努力,然后继续向你展示如何做到这一点。我将假设您可以提供以下算法:

  1. 以二进制方式读入的输入数字(因此&#34; 1101&#34;将以十进制数字读入&#34; 13&#34;)
  2. const vector<char> rooms
  3. 中的所有这些数字
  4. 每排&#34;房间的宽度&#34;可以放在size_t width(必须在所有行中保持一致,我们必须使用矩形的房间)
  5. 所有外墙&#34;墙壁&#34; &#34;房间&#34;将有一个&#34;墙&#34;
  6. 不到numeric_limits<int>::max()&#34;房间&#34;
  7. 我们会使用vector<int> temp标记每个房间,我们将构建rooms大小并将每个标签初始化为0. int result将被使用标记房间,并将初始化为0.但由于更换较小标签时所有房间标签都不会减少,size(set<int>(cbegin(temp), cend(temp)))将用于查找最终标签数。

    我们的解决方案将建立在2&#34; room&#34;其间没有墙;这样:

    1. 一个房间尚未贴上标签,在这种情况下会占用另一个房间的标签
    2. 两个房间共用一个标签,在这种情况下不会采取任何行动
    3. 一个房间的标签较小,在这种情况下,较大标签的所有房间都将被分配较小的标签
    4. 关于此功能的重要说明,我使用一元加运算符从L值int更多信息here构建R值int&。更明确的解决方案可能是使用static_cast<int>但由于某些原因,Visual Studio 2015无法按预期更多信息here工作。

      void generate(vector<int>& temp, int& target, const size_t width, const size_t i) {
          const auto replacement = temp[i];
      
          if (target > replacement) {
              replace(begin(temp), next(begin(temp), min(size(temp), i + width - 1)), target, replacement);
          } else {
              target = replacement;
          }
      }
      

      使用此代码我们可以:

      for (size_t i = 0U; i < size(rooms); ++i) {
          const auto toWest = (rooms[i] & 0b1000) == 0;
          const auto toNorth = (rooms[i] & 0b100) == 0;
          const auto toEast = (rooms[i] & 0b10) == 0;
          const auto toSouth = (rooms[i] & 0b1) == 0;
          const auto west = toWest && temp[i - 1] != 0 ? temp[i - 1] : numeric_limits<int>::max();
          const auto north = toNorth && temp[i - width] != 0 ? temp[i - width] : numeric_limits<int>::max();
          const auto east = toEast && temp[i + 1] != 0 ? temp[i + 1] : numeric_limits<int>::max();
      
          temp[i] = min({ temp[i] != 0 ? temp[i] : numeric_limits<int>::max(), result + 1, west, north, east });
      
          if (temp[i] == result + 1) ++result;
      
          if (toWest) generate(temp, temp[i - 1], width, i);
          if (toNorth) generate(temp, temp[i - width], width, i);
          if (toEast) generate(temp, temp[i + 1], width, i);
          if (toSouth) temp[i + width] = temp[i];
      }
      

      Live Example

答案 2 :(得分:2)

您的代码几乎没有问题,禁止正确的调试形式第三方,例如关于它如何工作的信息不足,未定义的变量(m,n,b)数组溢出(大量只有[411]的大量访问权限{ {1}}而不是411)阻止任何人开始尝试(让人怀疑代码是否真的有用并值得花时间)。我也很好奇,所以这里我的 BDS2006 Turbo C ++ BCB6 的继承者,所以这段代码也可以在那里工作)的简单未优化尝试。

<强> [rooms.h]

412

[单窗口VCL表单应用程序C ++源代码没有任何组件]

//---------------------------------------------------------------------------
#ifndef _rooms_h
#define _rooms_h
//---------------------------------------------------------------------------
class rooms
    {
public:
    // variables
    int xs,ys;          // map resolution
    DWORD **map;        // map[xs][ys]

    enum
        {
        _W=8,
        _N=4,
        _E=2,
        _S=1
        };

    // internals
    rooms();
    ~rooms();
    void _free();                                       // release map memory

    // inteface
    void resize(int _xs,int _ys);                       // realloc map to new resolution
    void set(AnsiString txt);                           // copy txt to map
    void draw(TCanvas *scr,int x,int y,int sz);         // draw map on Canvas at (x,y) with grid size sz
    int  count();                                       // count rooms
    };
//---------------------------------------------------------------------------
     rooms::rooms()     { map=NULL; xs=0; ys=0; }
     rooms::~rooms()    { _free(); }
//---------------------------------------------------------------------------
void rooms::_free()
    {
    if (map)
        {
        for (int x=0;x<xs;x++)
         if (map[x])
          delete[] map[x];
        delete[] map;
        }
    map=NULL; xs=0; ys=0;
    }
//---------------------------------------------------------------------------
void rooms::resize(int _xs,int _ys)
    {
    if ((xs==_xs)&&(ys==_ys)) return;
    _free();
    xs=_xs; ys=_ys;
    map=new DWORD*[xs];
    for (int x=0;x<xs;x++)
     map[x]=new DWORD[ys];
    }
//---------------------------------------------------------------------------
void rooms::set(AnsiString txt)
    {
    int i,l,x,y,n0,n1;
    l=txt.Length(); if (!l) return;
    // count eof lines (ys)
    for (y=0,i=1;i<=l;i++)
     if ((txt[i]==13)||(txt[i]==10))
        {
        y++;
        if (i<l)
         if ((txt[i+1]==13)||(txt[i+1]==10)) i++;
        }
     if ((txt[l]!=13)&&(txt[l]!=10)) y++;   // handle missing last eof
    // count numbers per line (xs)
    for (n1=0,x=0,i=1;i<=l;i++)
        {
        n0=n1; n1=0;
        if ((txt[i]=='0')||(txt[i]=='1')) n1=1;
        if ((txt[i+1]==13)||(txt[i+1]==10)) break;
        if ((!n0)&&(n1)) x++;
        }
    // copy data
    resize(x,y);
    for (x=0,y=0,i=1;i<=l;)
        {
        // skip spaces
        while ((i<=l)&&(txt[i]!='0')&&(txt[i]!='1')) i++;
        // read 4 bit bin number
        n0=  0; if (i>l) break; if (txt[i]=='1') n0|=1; i++;
        n0<<=1; if (i>l) break; if (txt[i]=='1') n0|=1; i++;
        n0<<=1; if (i>l) break; if (txt[i]=='1') n0|=1; i++;
        n0<<=1; if (i>l) break; if (txt[i]=='1') n0|=1; i++;
        map[x][y]=n0;
        x++; if (x>=xs) { x=0; y++; if (y>=ys) break; }
        }
    // clear the rest in case of error in data
    if ((y<ys)&&(x<xs)) for (;;)
        {
        map[x][y]=0;
        x++; if (x>=xs) { x=0; y++; if (y>=ys) break; }
        }
    }
//---------------------------------------------------------------------------
void rooms::draw(TCanvas *scr,int x0,int y0,int sz)
    {
    int x,y,xx,yy;
    DWORD a;

    scr->Brush->Color=clDkGray;
    scr->Brush->Style=bsSolid;
    scr->FillRect(Rect(x0,y0,x0+xs*sz,y0+ys*sz));

    scr->Pen->Color=clBlue;
    scr->Pen->Width=5;
    scr->Font->Color=clBlack;
    scr->Brush->Style=bsClear;
    for (xx=x0,x=0;x<xs;x++,xx+=sz)
     for (yy=y0,y=0;y<ys;y++,yy+=sz)
        {
        a=map[x][y]&15;
        if (DWORD(a&_W)) { scr->MoveTo(xx   ,yy   ); scr->LineTo(xx   ,yy+sz); }
        if (DWORD(a&_N)) { scr->MoveTo(xx   ,yy   ); scr->LineTo(xx+sz,yy   ); }
        if (DWORD(a&_E)) { scr->MoveTo(xx+sz,yy   ); scr->LineTo(xx+sz,yy+sz); }
        if (DWORD(a&_S)) { scr->MoveTo(xx   ,yy+sz); scr->LineTo(xx+sz,yy+sz); }
        scr->TextOutA(xx+(sz>>1),yy+(sz>>1),map[x][y]>>4);
        }
    scr->Brush->Style=bsSolid;
    scr->Pen->Width=1;
    }
//---------------------------------------------------------------------------
int  rooms::count()
    {
    int x,y,i,i0,i1,w0,w1,n,e;
    // each block is a separate room
    for (n=0,x=0;x<xs;x++)
     for (y=0;y<ys;y++,n+=16)
        {
        map[x][y]&=  0x0000000F;    // low 4 bits are walls
        map[x][y]|=n&0xFFFFFFF0;    // rest is room index
        } n>>=4;
    // reindex all indexes i0 to i1
    #define map_reindex(i0,i1)                      \
        for (x=0;x<xs;x++)                          \
         for (y=0;y<ys;y++)                         \
          if (DWORD(map[x][y]&0xFFFFFFF0)==i0)      \
            {                                       \
            map[x][y]&=   0x0000000F;               \
            map[x][y]|=i1&0xFFFFFFF0;               \
            }
    // loop until no change has occured
    for (e=1;e;)
        {
        e=0;
        // merge columns
        for (x=0;x<xs;x++)
         for (y=1;y<ys;y++)
            {
            w0=map[x][y-1]&0x0000000F;
            i0=map[x][y-1]&0xFFFFFFF0;
            w1=map[x][y  ]&0x0000000F;
            i1=map[x][y  ]&0xFFFFFFF0;
            if ((i0!=i1)&&(DWORD(w0&_S)==0)&&(DWORD(w1&_N)==0)) { map_reindex(i0,i1); n--; e=1; }
            }
        // merge rows
        for (y=0;y<ys;y++)
         for (x=1;x<xs;x++)
            {
            w0=map[x-1][y]&0x0000000F;
            i0=map[x-1][y]&0xFFFFFFF0;
            w1=map[x  ][y]&0x0000000F;
            i1=map[x  ][y]&0xFFFFFFF0;
            if ((i0!=i1)&&(DWORD(w0&_E)==0)&&(DWORD(w1&_W)==0)) { map_reindex(i0,i1); n--; e=1; }
            }
        }           

    return n;
    #undef map_reindex
    }
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

我的求解者背后的想法很简单:

  1. //$$---- Form CPP ---- //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "rooms.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; Graphics::TBitmap *bmp; // back buffer int xs,ys; // actual window resolution rooms map; // map of rooms //--------------------------------------------------------------------------- void draw() { int x,y,sz; // clear bachground bmp->Canvas->Brush->Color=clBlack; bmp->Canvas->Brush->Style=bsSolid; bmp->Canvas->FillRect(Rect(0,0,xs,ys)); // compute grid size x=(xs-20)/map.xs; sz=x; y=(ys-20)/map.ys; if (x>y) sz=y; // and map position so it is centered x=(xs-(sz*map.xs))>>1; y=(ys-(sz*map.ys))>>1; // render to backbuffer (avoid flickering) map.draw(bmp->Canvas,x,y,sz); // render backbuffer to window Form1->Canvas->Draw(0,0,bmp); } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner) { // init backbuffer bmp=new Graphics::TBitmap; bmp->HandleType=bmDIB; bmp->PixelFormat=pf32bit; // init map map.set("1101 0110 1101 0110 1100 0101 0110\r\n1110 1001 0110 1011 1010 1111 1010\r\n1000 0101 0011 1110 1011 1110 1010\r\n1011 1101 0101 0001 0101 0011 1011\r\n"); Caption=map.count(); // result count is in the Window Caption } //--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { delete bmp; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormPaint(TObject *Sender) { draw(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormResize(TObject *Sender) { // get actual window size xs=ClientWidth; ys=ClientHeight; // resize backbufer and force redraw bmp->SetSize(xs,ys); draw(); } //--------------------------------------------------------------------------- 每个网格单元格由不同的房间号

    请记住细胞计数为ID

  2. 合并所有相邻的房间,房间之间没有任何墙壁

    如此循环通过所有房间,如果任何相邻单元格没有挡墙,并且具有不同的房间n重新索引其房间号,那么展位房间具有相同的房间。同时减少房间柜台ID

  3. 循环#2,直到没有重新编制索引

  4. example

    <强> [注释]

    不要忘记在 IDE 中创建适当的事件,而不是仅仅复制代码,否则它将无效。

答案 3 :(得分:1)

一种简单的方法是创建一个具有房间大小的数组,并用&#34; 0&#34;初始化它。 之后你应该迭代数组。如果找到&#34; 0&#34;,则从该点开始BFS并将数组结果着色为当前数字。

有关BFS的信息

BFS必须寻找直接邻居并检查是否有&#34; 0&#34;在这个数组里面。如果是这样,BFS必须检查两个盒子之间是否有墙。如果中间没有墙,请使用当前颜色(在开头1)为此框添加颜色,并在新框中调用BFS。

当房间完全着色时,BFS会自动停止。那么全局颜色将增加1并且循环继续并寻找下一个&#34; 0&#34;。

在循环之后,房间的计数存储在全局颜色值中。

此算法适用于O(n)

小例子:

//CountingRooms.h
#include <vector>

class CountingRooms
{
public:
    CountingRooms();
    ~CountingRooms();
    int Count();

    void TestFill();
    void Print();
private:
    struct Point
    {
        int x = 0;
        int y = 0;
    };
    unsigned int* m_arrFieldColors = nullptr;
    unsigned int* m_arrFieldWalls = nullptr;
    int m_nSizeX = 0;
    int m_nSizeY = 0;
    int m_nCurrentColor = 0;

    unsigned int GetValue(unsigned int* field, int x, int y);
    void SetValue(unsigned int* field, int x, int y, unsigned int value);

    bool CanPass(int x1, int y1, int x2, int y2);
    void DFS(int posX, int posY);
    bool IsInsideArray(int x1, int y1); 
};



//CountingRooms.cpp
#include "stdafx.h"
#include "CountingRooms.h"
#include <iostream>

CountingRooms::CountingRooms()
{
}


CountingRooms::~CountingRooms()
{
    if (m_arrFieldColors)
    {
        delete[]m_arrFieldColors;
    }
    if (m_arrFieldWalls)
    {
        delete[]m_arrFieldWalls;
    }
}

bool CountingRooms::IsInsideArray(int x, int y)
{
    return x >= 0 && y >= 0 && x < m_nSizeX && y < m_nSizeY;
}

bool CountingRooms::CanPass(int x1, int y1, int x2, int y2)
{
    if (IsInsideArray(x1, y1) && IsInsideArray(x2, y2)) //inside the array range
    {
        if (x2 - x1 == 1 && y2 - y1 == 0) // right
        {
            if (!(GetValue(m_arrFieldWalls, x1, y1) & 2) && !(GetValue(m_arrFieldWalls, x2, y2) & 8)) { return true; }
        }
        if (x2 - x1 == 0 && y2 - y1 == -1) // up
        {
            if (!(GetValue(m_arrFieldWalls, x1, y1) & 4) && !(GetValue(m_arrFieldWalls, x2, y2) & 1)) { return true; }
        }
        if (x2 - x1 == -1 && y2 - y1 == 0) // left
        {
            if (!(GetValue(m_arrFieldWalls, x1, y1) & 8) && !(GetValue(m_arrFieldWalls, x2, y2) & 2)) { return true; }
        }
        if (x2 - x1 == 0 && y2 - y1 == 1) // down
        {
            if (!(GetValue(m_arrFieldWalls, x1, y1) & 1) && !(GetValue(m_arrFieldWalls, x2, y2) & 4)) { return true; }
        }
    }
    return false;
}

void CountingRooms::DFS(int posX, int posY)
{
    if (GetValue(m_arrFieldColors, posX, posY)) // check if the field is already colored
    {
        return;
    }
    Point sStart;
    sStart.x = posX;
    sStart.y = posY;
    std::vector<Point> vecList;
    vecList.push_back(sStart);

    m_nCurrentColor++;

    while (vecList.size()) // as long as something is inside the list
    {
        Point sTemp = vecList[vecList.size()-1]; //get out the last element
        vecList.pop_back();

        if (IsInsideArray(sTemp.x, sTemp.y))
        {
            if (!GetValue(m_arrFieldColors, sTemp.x, sTemp.y)) // is field not colored
            {
                SetValue(m_arrFieldColors, sTemp.x, sTemp.y, m_nCurrentColor);

                if (CanPass(sTemp.x, sTemp.y, sTemp.x + 1, sTemp.y)) /* right*/
                {
                    Point newPoint;
                    newPoint.x = sTemp.x + 1;
                    newPoint.y = sTemp.y;
                    vecList.push_back(newPoint);
                }
                if (CanPass(sTemp.x, sTemp.y, sTemp.x - 1, sTemp.y)) /* left*/
                {
                    Point newPoint;
                    newPoint.x = sTemp.x - 1;
                    newPoint.y = sTemp.y;
                    vecList.push_back(newPoint);
                }
                if (CanPass(sTemp.x, sTemp.y, sTemp.x, sTemp.y - 1)) /* up*/
                {
                    Point newPoint;
                    newPoint.x = sTemp.x;
                    newPoint.y = sTemp.y - 1;
                    vecList.push_back(newPoint);
                }
                if (CanPass(sTemp.x, sTemp.y, sTemp.x, sTemp.y + 1)) /* down*/
                {
                    Point newPoint;
                    newPoint.x = sTemp.x;
                    newPoint.y = sTemp.y + 1;
                    vecList.push_back(newPoint);
                }

            }
        }
    }
}

int CountingRooms::Count()
{
    m_nCurrentColor = 0;
    for (int i = 0; i < m_nSizeY; ++i)
    {
        for (int j = 0; j < m_nSizeX; ++j)
        {
            DFS(j, i);
        }
    }
    return m_nCurrentColor;
}

void CountingRooms::TestFill()
{
    m_arrFieldWalls = new unsigned int[42]{13, 6,13, 6,12, 5, 6,
                                           14, 9, 6,11,10,15,10,
                                            8, 5, 3,14,11,14,10,
                                           11,13, 5, 1, 5, 3,11};
    m_arrFieldColors = new unsigned int[42];
    for (int i = 0; i < 42;i++)
    {
        m_arrFieldColors[i] = 0;
    }
    m_nSizeX = 7;
    m_nSizeY = 4;

}

unsigned int CountingRooms::GetValue(unsigned int* field, int x, int y)
{
    if (IsInsideArray(x, y))
    {
        return field[x + m_nSizeX*y];
    }
    return -1;
}

void CountingRooms::SetValue(unsigned int* field, int x, int y, unsigned int value)
{
    if (IsInsideArray(x, y))
    {
        field[x + m_nSizeX*y] = value;
    }
}

void CountingRooms::Print()
{
    std::cout << "Walls:" << std::endl;
    for (int j = 0; j < m_nSizeY;++j)
    {
        for (int i = 0; i < m_nSizeX;++i)
        {
            std::cout << GetValue(m_arrFieldWalls, i, j) << "\t";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl<<"Colors:" << std::endl;

    for (int j = 0; j < m_nSizeY;++j)
    {
        for (int i = 0; i < m_nSizeX;++i)
        {
            std::cout << GetValue(m_arrFieldColors, i, j) << "\t";
        }
        std::cout << std::endl;
    }
}







//main.cpp
#include "stdafx.h"
#include <iostream>
#include "CountingRooms.h"

int main()
{
    CountingRooms cr;
    cr.TestFill();
    std::cout<<"There are "<<cr.Count()<<" rooms"<<std::endl;
    cr.Print();

    char key = 0;
    std::cin >> key;
    return 0;
}

btw:BFS被DFS取代,但两者都有效。

输出

enter image description here

答案 4 :(得分:1)

脱节设置以及联盟查找连接组件的问题非常匹配。而不是图表,我跟踪不同的不相交的地砖组。每个集合都有自己的代表性图块,用于唯一标识集合。

您可以详细了解Union-Find here

算法很简单:

  1. 对于每个图块,如果没有公共墙,则处理其相邻图块。这是使用两个图块中的简单union()完成的。完成后,每个图块将属于一个不相交的集合(每个集合代表连接的空间房间)。在附加的代码中,parent[]存储代表性元素。

    • 完成后,将每个磁贴的代表元素标准化。
  2. 计算唯一代表性元素的数量。这是不相交集的数量(因此连接空间的数量房间)。

  3. 其他一些观察结果:

    • 任何时候,您只需要处理北墙和西墙。 (为什么?证据留给读者。)

        

      这是因为对于图块a[i][j],其南墙和东墙可分别由图块a[i+1][j]a[i][j+1]处理。

    • 为什么我们需要规范每个瓷砖的代表?原因是一些集合最终可能有两个或更多代表性元素。我们递归地找到父元素以获得整个集合的唯一代表。 (如果要对此进行测试,请从附加的代码中注释掉以下行:

      // normalise each tile
      parent[i] = findSet(parent[i]);
      
    • 附加代码使用特殊版本的Union-Find和两种启发式方法:

      • 联盟排名(由ranks[]证明
      • 路径压缩

    附加代码:Live Example