这个问题是关于C ++ builder 6的代码。赏金对标准C ++算法感兴趣,以便在给定标准化输入的情况下解决问题(有关详细信息,请参阅this。) < / p>
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 代表一个房间:
假设:
numeric_limits<int>::max()
个房间 我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]) );
}
答案 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)
老实说,我真的很想尝试解决这个问题。所以我要说你在这方面做出了勇敢的努力,然后继续向你展示如何做到这一点。我将假设您可以提供以下算法:
const vector<char> rooms
size_t width
(必须在所有行中保持一致,我们必须使用矩形的房间)numeric_limits<int>::max()
&#34;房间&#34; 我们会使用vector<int> temp
标记每个房间,我们将构建rooms
大小并将每个标签初始化为0. int result
将被使用标记房间,并将初始化为0.但由于更换较小标签时所有房间标签都不会减少,size(set<int>(cbegin(temp), cend(temp)))
将用于查找最终标签数。
我们的解决方案将建立在2&#34; room&#34;其间没有墙;这样:
关于此功能的重要说明,我使用一元加运算符从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];
}
答案 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
//---------------------------------------------------------------------------
我的求解者背后的想法很简单:
//$$---- 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
合并所有相邻的房间,房间之间没有任何墙壁
如此循环通过所有房间,如果任何相邻单元格没有挡墙,并且具有不同的房间n
重新索引其房间号,那么展位房间具有相同的房间。同时减少房间柜台ID
。
循环#2,直到没有重新编制索引
<强> [注释] 强>
不要忘记在 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取代,但两者都有效。
输出
答案 4 :(得分:1)
脱节设置以及联盟查找与连接组件的问题非常匹配。而不是图表,我跟踪不同的不相交的地砖组。每个集合都有自己的代表性图块,用于唯一标识集合。
您可以详细了解Union-Find here。
算法很简单:
对于每个图块,如果没有公共墙,则处理其相邻图块。这是使用两个图块中的简单union()
完成的。完成后,每个图块将属于一个不相交的集合(每个集合代表连接的空间或房间)。在附加的代码中,parent[]
存储代表性元素。
计算唯一代表性元素的数量。这是不相交集的数量(因此连接空间的数量或房间)。
其他一些观察结果:
任何时候,您只需要处理北墙和西墙。 (为什么?证据留给读者。)
这是因为对于图块
a[i][j]
,其南墙和东墙可分别由图块a[i+1][j]
和a[i][j+1]
处理。
为什么我们需要规范每个瓷砖的代表?原因是一些集合最终可能有两个或更多代表性元素。我们递归地找到父元素以获得整个集合的唯一代表。 (如果要对此进行测试,请从附加的代码中注释掉以下行:
// normalise each tile
parent[i] = findSet(parent[i]);
附加代码使用特殊版本的Union-Find和两种启发式方法:
ranks[]
证明附加代码:Live Example