당신이 설명하는 것은 분할 문제 입니다. 실제로 해결되지 않은 문제라고 말해서 죄송합니다. 그러나 내가 추천하는 한 가지 방법은 Graph-Cut 기반 알고리즘입니다. Graph-Cut은 이미지를 로컬로 연결된 노드의 그래프로 나타냅니다. Max-flow-min-cut 정리 와 Ford Fulkerson 알고리즘을 사용하여 두 하위 구성 요소 사이의 경계가 최소 길이가되도록 그래프의 연결된 구성 요소를 재귀 적으로 세분화 합니다.
기본적으로 모든 워터 타일을 그래프로 연결합니다. 인접한 워터 타일 사이의 차이에 해당하는 그래프의 가장자리에 가중치를 지정하십시오. 나는 당신의 경우에 모든 가중치가 1 일 수 있다고 생각합니다. 바람직한 결과를 얻으려면 다른 가중치 체계를 사용해야합니다. 예를 들어 해안에 인접성을 포함하는 무게를 추가해야 할 수도 있습니다.
그런 다음 그래프의 연결된 모든 구성 요소를 찾으십시오. 이것들은 명백한 바다 / 호수 등입니다.
마지막으로, 연결된 각 구성 요소에 대해 두 개의 새로운 하위 구성 요소를 연결하는 모서리의 가중치 가 최소 가되도록 구성 요소를 재귀 적으로 세분화합니다 . 모든 하위 구성 요소가 최소 크기 (예 : 바다의 최대 크기)에 도달 할 때까지 또는 두 구성 요소를 절단하는 모서리의 무게가 너무 큰 경우 재귀 적으로 세분화하십시오. 마지막으로 남아있는 연결된 모든 구성 요소에 레이블을 지정하십시오.
이것이 실제로 할 일은 채널에서 서로 바다를 잘라내지만 큰 바다를 가로 지르는 것은 아닙니다.
여기 의사 코드가 있습니다.
function SegmentGraphCut(Map worldMap, int minimumSeaSize, int maximumCutSize)
Graph graph = new Graph();
// First, build the graph from the world map.
foreach Cell cell in worldMap:
// The graph only contains water nodes
if not cell.IsWater():
continue;
graph.AddNode(cell);
// Connect every water node to its neighbors
foreach Cell neighbor in cell.neighbors:
if not neighbor.IsWater():
continue;
else:
// The weight of an edge between water nodes should be related
// to how "similar" the waters are. What that means is up to you.
// The point is to avoid dividing bodies of water that are "similar"
graph.AddEdge(cell, neighbor, ComputeWeight(cell, neighbor));
// Now, subdivide all of the connected components recursively:
List<Graph> components = graph.GetConnectedComponents();
// The seas will be added to this list
List<Graph> seas = new List<Graph>();
foreach Graph component in components:
GraphCutRecursive(component, minimumSeaSize, maximumCutSize, seas);
// Recursively subdivides a component using graph cut until all subcomponents are smaller
// than a minimum size, or all cuts are greater than a maximum cut size
function GraphCutRecursive(Graph component, int minimumSeaSize, int maximumCutSize, List<Graph> seas):
// If the component is too small, we're done. This corresponds to a small lake,
// or a small sea or bay
if(component.size() <= minimumSeaSize):
seas.Add(component);
return;
// Divide the component into two subgraphs with a minimum border cut between them
// probably using the Ford-Fulkerson algorithm
[Graph subpartA, Graph subpartB, List<Edge> cut] = GetMinimumCut(component);
// If the cut is too large, we're done. This corresponds to a huge, bulky ocean
// that can't be further subdivided
if (GetTotalWeight(cut) > maximumCutSize):
seas.Add(component);
return;
else:
// Subdivide each of the new subcomponents
GraphCutRecursive(subpartA, minimumSeaSize, maximumCutSize);
GraphCutRecursive(subpartB, minimumSeaSize, maximumCutSize);
편집하다 : 그런데, 모든 가장자리 무게가 1 인 경우 최소 해수 크기가 약 40으로 설정되고 최대 절단 크기가 1 인 예제에서 알고리즘이 수행하는 작업은 다음과 같습니다.
파라미터를 사용하여 다른 결과를 얻을 수 있습니다. 예를 들어, 최대 절단 크기가 3이면 주요 바다에서 더 많은 베이가 조각되고 바다 # 1이 북쪽과 남쪽의 절반으로 세분화됩니다. 최소 바다 크기가 20이면 중앙 바다도 절반으로 나뉩니다.