我想知道我应该在这里应用哪种算法。 DFS会这么做吗?
给出2-d矩阵。找到该矩阵中连接集的总数。
连接集可以被定义为其中提到1并且在该集合中具有至少一个其他小区的小区组,它们与它们共享邻居关系。其中包含1并且没有周围邻居的小区可以被认为是其中包含一个小区的集合。可以将邻居定义为在8个可能方向(即,N,W,E,S,NE,NW,SE,SW方向)上与给定小区相邻的所有小区。一个小区不是它自己的邻居。
例如:
1 0 0 1
0 0 1 0
0 0 1 0
1 0 0 1
连接数量为3
0 0 1 0 0 1 0 0
1 0 0 0 0 0 0 1
0 0 1 0 0 1 0 1
0 1 0 0 0 1 0 0
1 0 0 0 0 0 0 0
0 0 1 1 0 1 1 0
1 0 1 1 0 1 1 0
0 0 0 0 0 0 0 0
连接数量为9。
答案 0 :(得分:7)
我认为您不需要将其视为一般图形问题并应用任何算法,例如BFS或DFS。
您需要对矩阵进行三次扫描。
扫描1:
从顶部开始
1 0 0 2
,您的示例应如下所示
1 0 0 2
0 0 2 0
0 0 2 0
3 0 0 2
扫描2:
从底部开始 检查每个邻居是否与最左边邻居的号码相同,以及与下面一行中邻居的号码相同
基本上如果你有这样的矩阵
1 0 2
1 0 2
0 1 0
检查确保一组具有真正相同的数字
扫描3:
计算矩阵中唯一非0条目的数量
答案 1 :(得分:3)
Connected-component labeling算法旨在标记连接的元素组(包括4连接和8连接)
答案 2 :(得分:1)
您想使用disjoint set数据结构和算法。这将为每个连接的组件选择一个唯一的代表,您可以在最后计算。
为了有效地评估哪些元素是邻居,您可以逐行扫描矩阵,维护上一行(连续1
)的段列表,同时确定哪些段当前行与它们相邻。
答案 3 :(得分:1)
有3组连接。彼此相邻的所有1个被认为是一个单独的集合。 a[1,4]
,a[2,3]
,a[3,3]
和a[4,4]
的所有1个形成一个集合,一个a[1,1]
形成一个集合,一个a[4,1]
形成一个集合集。
答案 4 :(得分:1)
Pythonic实现,更易理解的代码:
# sea is 2 D array of 0 and 1s we have to find 1's group surrounded by 0's
def dfs(sea, i, j, b, h, visited):
surround = ((-1, -1), (0, -1), (1, -1),
(-1, 0), (1, 0),
(-1, 1), (0, 1), (1, 1)
)
if can_visit(sea, i, j, b, h, visited):
for s in surround:
visited[(i, j)] = 1
dfs(sea, i + s[0], j + s[1], b, h, visited)
def can_visit(sea, i, j, b, h, visited):
if i >= 0 and j >= 0 and i < b and j < h:
if (i, j) not in visited and sea[i][j] == 1:
return True
def find_island(sea):
visited = {}
h = len(sea)
count = 0
for i, row in enumerate(sea):
b = len(row)
for j, item in enumerate(row):
if can_visit(sea, i, j, b, h, visited):
count += 1
dfs(sea, i, j, b, h, visited)
return count
sea = [[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[1, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[1, 0, 1, 0, 1]
]
print find_island(sea)
答案 5 :(得分:0)
扫描矩阵1秒。找到一个时,调用一个递归函数,如果它尚未被识别为一个,则标记其连接的组件。使用递归查找连接的组件。在某处快速查找,告诉您某个给定节点是否已被识别为连接组件,以避免识别连接组件2x,并避免在遍历连接组件时出现无限循环。
答案 6 :(得分:0)
如果你想通过你的矩阵(没有额外的记忆)来做,请按照以下步骤进行:
将扫描仪位置设置为[0,0]
1
并将扫描仪位置设置为1
之后的下一个元素,如果没有{{1}转到第6步。1
并递归查找其所有counter+2
个邻居,并将其设置为1
。count + 2
count = count + 1
。PS:很清楚扫描仪的位置是否大于算法结束的矩阵大小(我没有写这个以防止混淆)。
答案 7 :(得分:0)
这并不像它看起来那么难。事实上,这非常像教授在第一年的计算机科学专业分配的东西。所以,如果这是作业,你应该这样标记。
然而,解决方案相当容易。
for (int y = 0; y < arr.height(); y++)
{
for (int x = 0; x < arr.width(); x++)
{
if (arr[x][y] == 1)
{
if (CheckIfConnected(x, y, arr))
{
connectedPositionsX.Add(x);
connectedPositionsY.Add(y);
}
}
}
}
其中connectedPositions是链接列表或您想要存储的任何设置。
arr
是一个2D数组,包含您在上面指定的类型的矩阵。
CheckIfConnected也可以相当简单地实现。
bool CheckIfConnected(int x, int y, int[][]arr)
{
if (arr.width() >= 2) || (arr.height() >= 2)
{
if ((x < arr.width()) && (x >= 0) && (y < arr.height()) && (y >= 0))
{
if ((x-1) >= 0) //West
{
if (arr[x-1][y] == 1)
{
adjCount[x-1][y] += 1;
return true;
}
}
if (((x-1) >= 0) && ((y-1) >= 0)) //Northwest
{
if (arr[x-1][y-1] == 1)
{
adjCount[x-1][y-1] += 1;
return true;
}
}
if ((y-1) >= 0) //North
{
if (arr[x][y-1] == 1)
{
adjCount[x][y-1] += 1;
return true;
}
}
if (((x+1) < arr.width()) && ((y-1) >= 0)) //Northeast
{
if (arr[x+1][y-1] == 1)
{
adjCount[x+1][y-1] += 1;
return true;
}
}
if ((x+1) < arr.width()) //East
{
if (arr[x+1][y] == 1)
{
adjCount[x+1][y] += 1;
return true;
}
}
//I'll let you implement Southeast to Southwest on your own,
//the pattern is clear now.
}
}
return false;
}
从那里,您知道在网格中每个位置找到配对的次数。这有助于您跟踪您的连接。
2D数组adjCount
中的计数会为您追踪这一点。
你也可以通过修改Dijkstra的算法来递归地为你做。既然你提到了DFS(深度优先搜索),我假设你的教授或老师希望你这样解决它。
在那种情况下:
这是Dijkstra在伪代码中的算法: http://en.wikipedia.org/wiki/Dijkstra“s_algorithm
希望有所帮助!干杯!
答案 8 :(得分:0)
只需在值为1的每个节点上以递归方式继续搜索东,东南,南和西西方向。 如果对访问函数的调用是一个新的调用而不是来自递归,则增加连接的组件。
import java.util.Scanner;
public class Solution {
public static void visit(int[][] ar, boolean[][] v,int i, int j){
int size = ar.length;
if(ar[i][j] == 1){
v[i][j] = true;
if(j>0 && i<size-1){
visit(ar,v,i+1,j-1); // SouthWest
}
if(i<size-1){
visit(ar,v,i+1,j); // South
if(j < size-1)
visit(ar,v,i+1,j+1); // SouthEast
}
if(j<size-1)
visit(ar,v,i,j+1); // East
}
}
public static void main(String[] args) {
int[][] ar;
int count = 0;
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
ar = new int[n][n];
boolean[][] v = new boolean[n][n];
for(int i=0; i<n ; i++) {
for(int j=0; j<n; j++){
ar[i][j] = sc.nextInt();
v[i][j] = false;
}
}
for(int i=0; i<n ; i++) {
for(int j=0; j<n; j++){
if(ar[i][j] == 1 && !v[i][j]){
count++;
visit(ar,v,i,j);
}
}
}
System.out.println(count);
}
}
答案 9 :(得分:0)
我有一个类可以帮助您找到2D阵列中连接组件的总数。我的班级不仅可以为您提供总数,还可以为您提供聚类并为您提供可视化。您可以注释掉您不需要的部分。请在(java)中查看此课程:https://github.com/m-vahidalizadeh/foundations/blob/master/src/algorithms/ConnectedComponetns.java
答案 10 :(得分:0)
对于python尝试:
import numpy
from scipy import ndimage
data = [[0, 0, 1, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 1, 0, 1],
[0, 1, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 1, 1, 0],
[1, 0, 1, 1, 0, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
label, index = ndimage.label(data, numpy.ones((3, 3)))
print(label, index)
[[0 0 1 0 0 2 0 0]
[3 0 0 0 0 0 0 4]
[0 0 5 0 0 6 0 4]
[0 5 0 0 0 6 0 0]
[5 0 0 0 0 0 0 0]
[0 0 7 7 0 8 8 0]
[9 0 7 7 0 8 8 0]
[0 0 0 0 0 0 0 0]] 9