我在网站上看到了这个编程难题,并试图解决它。
问题
您将获得一个N x N网格,其中有一些点随机分布。您必须使用以下允许的操作删除这些点
您可以一次性删除一行中的所有点
或者您可以一次性删除列中的所有点。
你必须找到删除所有点所需的最小镜头数。
实施例
在以下网格中,您需要三次拍摄 - 一次水平拍摄,两次垂直拍摄以取消点。
我尝试了一种方法,用点来计算行和列,最小的是答案。但是在特定情况下它会失败,如上例所示。 这样做的方法是什么,或者是否存在类似于我可以参考解决此问题的任何情况?
修改
给出的约束是
1 <= N <= 1000
0 <= x,y <= 10^9
Time Limit: 2 sec
其中n是网格的维度(即nxn),x,y是坐标
答案 0 :(得分:1)
将2D网格转换为二分图。左侧包含节点表示行,右侧包含节点表示列。对于包含点的每个单元格,假设它的坐标为(x,y),添加链接row_x和column_y的边。建立二分图后,使用匈牙利算法获得最大匹配。因为在二分图中,最大匹配的答案等于最小顶点覆盖,这正是你想要的。
匈牙利算法是O(V * E)算法。有关详细信息,请参阅Hungarian algorithm
有关二分图的更多信息,请参阅Bipartite graph,您可以找到为什么最大匹配等于此处覆盖的最小顶点。
答案 1 :(得分:0)
我会尝试一种详尽的算法。如果你做得对,它并没有听起来那么糟糕。
你已经知道,在最坏的情况下,它需要N次射击(如果你在每一行或每一列射击,它肯定会起作用。)
因此,为了改善更糟糕的情况,您只需要尝试所有可能的列镜头+行镜头的排列,其中总镜头数小于N.例如,如果N = 4,则必须使用非平凡的解决方案be&lt; = 3,所以尝试所有(列,行)镜头:
(0,3)
(1,2)
(2,1)
(3,0)
对于您想拍摄的任何轴(列或行),有(s choose N)
种可能性。因此,大N的可能性的总数类似于(N/2) choose N
,这对于N&lt; 30无论如何。
我确信有更好的启发式算法,并且可能还有更好的案例算法。
答案 2 :(得分:0)
我认为这里可能会应用递归。我不认为它是有效的,但跟随是一个你可以使用的想法。
从左上角点开始。您有以下方案:
同一行和同一列中有另一个点。 - &GT;分支到三种可能性
同一行中有另一个点但不在同一列中。 - &GT;拍摄此行,删除同一行中的所有点并移动到下一个点。
同一列中有另一个点,但不在同一行.-&gt;拍摄此列,删除同一列中的所有点并移动到下一个点。
同一列或同一行中没有点。 - &GT;射击行或列,没关系,继续下一个点。
对于第一种情况,分支必须完成如下操作:
int minimumNumberOfLines( matrixOfDots ) {
return min( 1 + minimumNumberOfLines( with row shot ),1 + minimumNumberOfLines( with col shot ), 2 + minimumNumberOfLines( with row and column shot ) ).
}