覆盖网格中单元所需的最小激光数量?

时间:2014-05-01 20:34:12

标签: algorithm

我在接受采访时被问到这个问题。我正在修改这个问题以保护它不被明确表示为Google,但要点是:

您将获得N x M网格。网格中的一些单元格是“邪恶的”(用数字1表示),其余的是“好”(用0表示)。您可以在每个N行和每个M列中放置激光,这些激光在打开时会杀死其各自行或列中的所有单元格,例如如果你有:

   L1 L2 L3 L4
L5  0  1  0  0
L6  0  1  0  1
L7  0  1  1  0
L8  0  0  0  0

你可以打开(L2,L3,L4):

   L1 L2 L3 L4
L5  0  x  x  x
L6  0  x  x  x
L7  0  x  x  x
L8  0  x  x  x

或者你可以打开(L2,L6,L7):

   L1 L2 L3 L4
L5  0  x  0  0
L6  x  x  x  x
L7  x  x  x  x
L8  0  x  0  0

如果它杀死了所有邪恶的细胞,那么一组激光被打开称为“GoodConfig”。请注意,你可以随时打开一行或一列的所有激光并杀死所有东西,这将是“GoodConfig”,但开启激光是昂贵的,杀死好的细胞是不好的。

  1. “GoodConfig”的最小尺寸是多少,即我们可以打开最少数量的激光直到杀死所有邪恶细胞?

  2. 什么是“GoodConfig”,可以最大限度地减少杀死的好细胞数量?

2 个答案:

答案 0 :(得分:9)

这个问题可以重新表述为二分图上的最小顶点覆盖问题。

考虑一个图:顶点是行(一部分)和列(另一部分)。当且仅当相应的单元格row是邪恶的时候,顶点col(row, col)之间存在边缘。

我们现在的问题是找到一组具有最小可能尺寸的顶点,这样我们图形的每个边(前一个单元格)在我们的集合(行或列)中至少有一个顶点。

根据Koenig's Theorem,我们可以在二分图中找到最大匹配,然后恰好标记匹配的每个边的一个顶点,以便得到的顶点集覆盖上述意义上的图。特别是,最大匹配的大小等于最小顶点覆盖的大小。

答案 1 :(得分:2)

为了回答1)和2),我会采用以下方法,假设N或M很小(比如说< = 25)。

选择了一组行/列(以较小者为准)的暴力,并检查相应的成本添加列/行以涵盖所有内容。

假设N <= M,有2个 N 行,我们处理每个行的整个矩阵。该方法在O(2 N * N * M)中运行。

#define CONTAINS(mask, bit) (mask & (1 << bit))

void Solve(int matrix[MAX][MAX], int N, int M) {
    vector<int> best;
    int i, j, best_good_cells;
    for (int rows_mask = 0; rows_mask < (1 << N); rows_mask++) {
        vector<int> lasers;
        int good_cells = 0;
        for (j = 0; j < M; j++) {
            bool add_column = false;
            int good = 0;
            for (i = 0; i < N; i++)
                if (!CONTAINS(rows_mask, i)) {
                    if (matrix[i][j] == 0)
                        good++;
                    else
                        add_column = true;
                }
            if (add_column) {
                lasers.push_back(j);
                good_cells += good;
            }
        }
        for (i = 0; i < N; i++)
            if (CONTAINS(rows_mask, i))
                lasers.push_back(M+i);
        if (best.size() == 0 ||
                best.size() > lasers.size() ||
                (best.size()==lasers.size() && good_cells < best_good_cells)){
            best = lasers;
            best_good_cells = good_cells;
        }
    }
    cout << "Select lasers:";
    for (auto i: best)
        cout << " " << i+1;
    cout << endl;
}