Algorithm 覆盖网格中细胞所需的最小激光数量?

Algorithm 覆盖网格中细胞所需的最小激光数量?,algorithm,Algorithm,我在一次采访中被问到这个问题。我对这个问题做了一些修改,以避免它被明确地谷歌搜索到,但要点是: 您将获得一个nxm网格。网格中的某些单元格是“邪恶”(用数字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):

我在一次采访中被问到这个问题。我对这个问题做了一些修改,以避免它被明确地谷歌搜索到,但要点是:

您将获得一个
nxm
网格。网格中的某些单元格是“邪恶”(用数字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):

或者您可以打开(L2、L6、L7):

如果一组激光器能够杀死所有邪恶的细胞,那么它就被称为“GoodConfig”。请注意,您始终可以打开一行或一列的所有激光器并杀死所有东西,这将是“GoodConfig”,但打开激光器是昂贵的,杀死好的细胞是不好的

  • “GoodConfig”的最小尺寸是多少,即在杀死所有邪恶细胞之前我们可以打开的激光器的最少数量

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


  • 这个问题可以转化为二部图上的最小顶点覆盖问题

    考虑一个图形:顶点是行(一部分)和列(另一部分)。当且仅当对应的单元格
    (行,列)
    为邪恶时,顶点
    之间存在一条边

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


    根据,我们可以在我们的二部图中找到最大匹配,然后在匹配的每一条边上精确地标记一个顶点,从而得到的顶点集覆盖了上述意义上的图。特别是,最大匹配的大小等于最小顶点覆盖的大小。

    为了回答1)和2),我将采用以下方法,假设N或M很小(say看起来本质上是一样的。当R=C=1@01时看起来像这个问题。Zhou:我似乎记得与TopCoder的问题完全相同,电路板尺寸高达18x18(因此2^18*18的解决方案也会通过),但目前找不到它。我认为18太低了……问题似乎非常接近于在O(n^3)中运行的匈牙利算法,您可能可以轻松地在n=1000时运行它。@wrick:当然,在O(n^3)中,二部匹配(以及二部最小顶点覆盖)很简单,在O(n^2*sqrt(n))中有点技术性。请注意“这样2^18*18的解决方案也会通过"我的评论的一部分。我删除了对另一种方法的批评。我不同意原始版本没有回答这个问题,但我详细阐述了这个版本。向下投票是因为问题有一个多项式时间解,这太慢了。Gassa没有明确提到它,但找到了稠密二部图的最小顶点覆盖h有一个次三次算法(因为一般问题是NP难的,所以这里的关键是二分体).我知道最小顶点覆盖部分。我的观点是,它只回答最小数量的激光。如果有多个配置具有最小值,则二分匹配算法将选择其中任何一个-它不会最小化被杀死的好细胞数(问题2)。fixmeasap已证明2)在这里是NP难的:
       L1 L2 L3 L4
    L5  0  x  x  x
    L6  0  x  x  x
    L7  0  x  x  x
    L8  0  x  x  x
    
       L1 L2 L3 L4
    L5  0  x  0  0
    L6  x  x  x  x
    L7  x  x  x  x
    L8  0  x  0  0
    
    #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;
    }