(Возможный) контрпример к общему минимальному покрытию вершин на дереве Алго и мой подход

В прошлом было много сообщений на эту тему из быстрого поиска на сайте, многие из которых используют это повторение динамического программирования:

C (x) = min (1 + сумма (C (i) для i у детей x), len (дети x)) + sum(C(i) для i у внуков x))

Предполагая, что дерево укоренено в узле 1, я попробовал этот алгоритм для цепочки узлов 1-2-3-4-5-6, чтобы получить следующий C (i):

| C(1) | C (2) | С (3) | C (4) | C (5) | C (6) |

| 3 | 2 | 2 | 1 | 1 | 1 |

Тем не менее, правильный ответ для C(1) должен быть 2, что достигается путем маркировки узлов 2 и 5.

Я решил попробовать свой собственный подход, который подробно описан ниже:

int solve(int curr, int height){
    if(dp[curr][height] > -1) return dp[curr][height];
    if(int(children[curr].size()) == 0) return dp[curr][height] = height > 1 ? 1 : 0;
    if(height == 3){
        int ret = 1;
        for(int i = 0; i < int(children[curr].size()); i++){
            int next = children[curr][i];
            ret += solve(next, 1);
        }
        return dp[curr][height] = ret;
    }
    int ret1 = 0; int ret2 = 1;
    if(height == 2){
        for(int i = 0; i < int(children[curr].size()); i++){
            int next = children[curr][i];
            ret1 += solve(next, 3); ret2 += solve(next, 1);
        }
        return dp[curr][height] = min(ret1, ret2);
    }
    for(int i = 0; i < int(children[curr].size()); i++){
        int next = children[curr][i];
        ret1 += solve(next, 2); ret2 += solve(next, 1);
    }
    return dp[curr][height] = min(ret1, ret2);
}

curr - текущий узел, в котором мы находимся, а height - это расстояние от ближайшего отмеченного узла над ним. Идея состоит в том, что, как только узел имеет высоту = 3, он должен быть отмечен в этом конкретном пути. В противном случае мы можем пропустить пометку на данный момент. Исключением является листовой узел, который должен быть помечен, если соседний узел не помечен.

Может кто-нибудь проверить правильность моего подхода, а также объяснить, почему первый алгоритм не проходит цепной тест?

Заранее спасибо!

1 ответ

Решение

Первый алгоритм действительно работает. В минимальном покрытии вершин каждое ребро должно быть инцидентно как минимум одной вершине. В вашем "контрпримере" не отмечены ни вершины 3, ни 4, поэтому у ребра (3,4) нет вершины в наборе. Таким образом, {2, 5} не является покрытием вершин.

Ваш подход не работает вообще. Прежде всего, я думаю, что вы все еще работаете с неправильным определением минимального покрытия вершин. Я предполагаю, что вы думаете, что каждая вершина должна касаться края, падающего на отмеченную вершину.

И даже если вы используете неправильное определение, ваш подход не будет работать. Вершина с расстоянием 3 до отмеченной родительской вершины не должна быть отмечена. Посмотрите на этот пример:

  0
  |
  1
  |
  2
 / \
3   4
    |
    5

В этом примере, если отмечена вершина 0, вершины 3 и 4 также помечаются, потому что они находятся на расстоянии 3 от вершины. Но нет необходимости отмечать вершину 4, вместо этого мы могли бы также отметить вершину 5. Очевидно, что в этом примере это даст такое же количество вершин, но я уверен, что вы могли бы расширить это на более крупный пример, где ваш подход терпит неудачу.

Идея решения для другого определения:

Я считаю, что жадное решение работает. (Существует также жадный алгоритм для минимального покрытия вершин). Начните с листьев иди вверх к центру. Отметьте только те узлы, которые необходимо пометить.

Вы можете сделать это снова с глубиной поиска и DP. Пусть dp[v] будет кратчайшим расстоянием между v и отмеченным узлом в поддереве v. Чтобы вычислить v, сначала вычислите все значения dp дочерних узлов, а затем решите, нужно ли это отмечать или нет. Если у любого ребенка dp[child] = 2, вам нужно отметить v и поставить dp[v] = 0. В противном случае вам не нужно отмечать его и dp[v] = min(dp[children] + 1), В конце вам также может понадобиться отметить корневой узел.

Примечание: я не проверял это.

Другие вопросы по тегам