使用给定的最小权重最大化子图的数量

时间:2014-12-08 20:59:36

标签: algorithm theory graph-theory weighted

我有一个无向平面图,每个节点都有一个权重。我希望将图形分成尽可能多的连接不相交的子图(编辑:或者达到子图的最小平均权重),条件是每个子图必须达到固定的最小权重(这是一个权重之和)其节点)。只包含单个节点的子图也可以(如果节点的权重大于固定的最小值)。

到目前为止我发现的是一种启发式方法:

create a subgraph out of every node
while there is an underweight subgraph:
  select the subgraph S with the lowest weight
  find a subgraph N that has the lowest weight among the neighbouring subgraphs of S
  merge S to N

显然,这不是最佳选择。有没有人有更好的解决方案? (也许我只是无知,这不是一个复杂的问题,但我从未研究过图论......)

编辑(更多背景细节):此图中的节点是要为其提供统计数据的低规模管理单位。但是,这些单位需要有一定的最小人口规模,以避免与个人数据立法发生冲突。我的目标是创建聚合,以便在途中丢失尽可能少的信息。邻域关系充当图边,因为结果单元必须是连续的。

集合中的大多数单元(节点)都远高于最小阈值。其中约5-10%低于阈值,大小不同,如示例所示(最小尺寸50):

Example situation

3 个答案:

答案 0 :(得分:5)

这是一个NP难的优化问题。例如,Partition problem可以很容易地减少(平面性属性不会引起问题)。因此,计算最佳解决方案的算法(并且您似乎要求在评论中提出最佳解决方案)对于成千上万个节点来说不太可行。"

如果你真的不需要一个最佳的解决方案而是一个好的解决方案,我会使用局部优化方法,例如禁忌搜索或模拟退火。

因为子图的平均权重只是总图的权重除以子图的数量,所以唯一重要的是找到你可以达到的最大子图数。猜测这个数字N,形成一个初始划分为N个子图,然后,例如,使用局部移动(1)将一个节点从一个子图移动到另一个子图和(2)在两个相邻子图之间交换两个节点,以寻找一个可接受的解决方案,每个子图都有所需的最小重量。如果您根本找不到可接受的解决方案,请减少N(例如减1)并重新启动,直至找到解决方案。

答案 1 :(得分:2)

实例的细节会改变一切。

如果顶点,则它自身超过阈值。拥有一个带有两个重顶点的子图是没有意义的,因为我们可以将它分成两个。因此,最优解中子图的数量与不包含重顶点的子图的数量相关。

因此,我们可以删除重顶点,并专注于从剩下的内容中制作尽可能多的有效子图。根据你的地图判断,左边的内容将包含许多连通的组件,每个组件只有少数几个顶点。必须连接有效的子图,因此可以独立地解决这些组件。在小实例上,可以(例如)枚举所有有效的子图,然后运行Algorithm X以找到最大基数包装。

答案 2 :(得分:1)

问题是NP难,然后我将强调一个指数解决方案。这个解决方案有很多改进点,我会强调一些。

整个想法是:顶点的每个分区都通过一些边连接,然后你可以确保如果你尝试使用所有可能的边集来创建图的正确分区。您可以找到计算每个分区数量的最佳情况(最佳条件)。

在您之前的方法中,您没有域来扩展搜索范围。对于解决方案使用以下内容: - 不相交集:分区表示 - 功率集:用于查找所有可能的边集

public Partition Solve(Graph g, int min)
{
    int max = 0;
    Partition best;

    // Find all the possible partitions for Edges
    foreach(var S in PowerSet(g.Edges))
    {
        // Build the Vertexes partition
        var partition =  BuildPartition(S);

        // Test the min condition foreach component
        if (IsInvalid(partition, min))
            continue;

        // Continue if we already have something better
        if (max >= partition.Length)
            continue;

        // Update
        max = partition.Length;
        best = partition;
    }

    return best;
}

public Partition BuildPartition(Graph g, IEnumerable<Edge> edges)
{
    // Initially Every Vertex in alone in his partition
    var partition = new DisjointSet(g.Vertexes);

    foreach (var edge in edges)
    {
        // If the Vertexes of this edge are already in the same partition DO NOTHING
        if (partition.Find(edge.V1) == partition.Find(edge.V2))
            continue;

        // Join both subsets
        partition.Union(edge.V1, edge.V2);
    }

    return parition;
}

public bool IsInvalid(Partition p, int min)
{
    return p.Sets.Any(t => t.Sum(v => v.Weight) < min);
}

您可以在以下方面改进解决方案: - 为PowerSet和IsInvalid条件添加并行性 - 找到生成有效边集的更好方法 - 有一些Vertex的起始案例,其权重大于最小值(总是在一个单独的子图中)

算法的顺序由Power Set给出。 - 功率集:在这种情况下,对于N顶点图,您将在最坏的情况下具有3N-6个边,然后是O(2 ^ N)。 - 构建分区:V + E * LogV则为O(NLogN) - IsInvalid:O(V)

最后Solve是O(2 ^ N * N * LogN) 使用最后一个公式来计算操作次数

希望这个帮助!