【问题标题】:Minimum number of lasers required to cover cells in grid?覆盖网格中的单元所需的最少激光器数量?
【发布时间】:2014-05-01 20:34:11
【问题描述】:

我在一次采访中被问到这个问题。我正在稍微修改这个问题,以防止它被明确地谷歌,但要点是:

给你一个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”,可以最大限度地减少被杀死的好细胞的数量?

【问题讨论】:

  • This question 似乎基本相同。
  • 当R=C=1 community.topcoder.com/stat?c=problem_statement&pm=12447时看起来像这个问题
  • @01zhou:我似乎记得与 TopCoder 上的问题完全相同的问题,电路板尺寸高达 18x18(这样 2^18 * 18 的解决方案也可以通过),但找不到就在此刻。
  • 我认为 18 太低了......这个问题似乎非常接近运行在 O(n^3) 中的匈牙利算法,你可以轻松地运行它 n = 1000。
  • @wrick:当然,二分匹配(和二分最小顶点覆盖)在 O(n^3) 中很简单,在 O(n^2*sqrt(n)) 中更技术性一点。请注意我评论中的“这样 2^18 * 18 的解决方案也会通过”部分。

标签: algorithm


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    对选定的行/列集(以较小者为准)进行暴力破解,并检查添加列/行以覆盖所有内容的相应成本。

    假设 N N 组行,我们为每一行处理整个矩阵。这种方法在 O(2N * 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;
    }
    

    【讨论】:

    • 我删除了对另一种方法的批评。我不同意原始版本没有回答问题,但我对此版本进行了详细说明。
    • 投反对票,因为这个问题有一个多项式时间解决方案,这太慢了。
    • Gassa 没有明确提及,但是找到密集 bipartite 图的最小顶点覆盖有一个 subcubic 算法(bipartite 是这里的关键,因为一般问题是NP 难)。
    • 我知道最小顶点覆盖部分。我的观点是它只回答最少量的激光。如果有多个具有最小值的配置,二分匹配算法将选择其中任何一个 - 它不会最小化被杀死的好细胞的数量(问题 2)。
    • fixmeasap 已经证明 2) 在这里是 NP-hard:apps.topcoder.com/forums/?module=Thread&threadID=817858
    猜你喜欢
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多