@Proshka17

Как понять условие задачи?

Добрый день!
Есть задача
Код:
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <functional>
#include <string>
#include <algorithm>
using namespace std;



class Sol {
public:
  long long max = -1;


};

int main() {
  ifstream f("input.txt");
  Sol s;
  string nodes;
  string rebr;
  f >> nodes;
  f >> rebr;
  for (long long i = 0; i < stoll(rebr); i++) {
    string fr;
    string to;
    string we;
    f >> fr;
    f >> to;
    f >> we;
    if (stoll(we) > s.max) s.max = stoll(we);
  }
  cout << s.max;
 

  return 0;
}
  • Вопрос задан
  • 285 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Что вы не поняли в решении: вы оптимизируете «чёрную» половинку графа, забыв, что самое малое ребро может быть в «белой».

ДЛЯ КАЖДОЙ ВЕРШИНЫ: ук-ль на «начальника» + флаг инверсии. Если у вершины нет начальника — то указывает в null.
ДИРЕКТОРОМ назовём вершину, у которого нет начальников. Считаем также, что у директора флаг инверсии всегда false.

Заведём функцию getInfoNonDestructive, она возвращает структуру из двух элементов. Во-первых, это директор (никогда не null!!). Во-вторых, это цвет — XOR флагов инверсии от самóй вершины до директора.

Функция getInfo вызовет getInfoNonDestructive, а затем проведёт ОПТИМИЗАЦИЮ СТРУКТУРЫ: ЕСЛИ вершина имеет начальника, ТО: начальник вершины := директор, флаг инверсии вершины := цвет вершины.

СЛИЯНИЕ фирм происходит так. Директор фирмы становится подчинённым кому-то из членов другой фирмы.

ИЗНАЧАЛЬНО для всех вершин начальник — null, флаг инверсии — false. То есть каждая вершина белая и сама себе директор.
РЕШЕНИЕ: Отсортируем рёбра в порядке возрастания.
Для каждого ребра…
• Находим информацию о вершинах — концах ребра.
• Если директор один и цвета разные — ничего не делаем.
• Если директор один и цвет один — выводим вес этого ребра как ответ.
• Если директора разные — сливаем фирмы. Подкручиваем флаг инверсии того директора, который исчез, так, чтобы цвета вершин — концов ребра были разные. Хотя бы так.
VertexInfo info1 = getInfo(vertex1);
VertexInfo info2 = getInfo(vertex2);
if (…) {
  info1.director->superior = info2.director;
  VertexInfo info1new = getInfoNonDestructive(vertex1);
  if (info1new.color == info2.color)
    info1.director->inverseFlag = !info1.director->inverseFlag;
}

ВНИМАНИЕ, без оптимизации структуры сложность с «чуть более O(N)» превращается в N²! Но конкретно в этом месте важно получить инфу без разрушений — временно запрещается кого бы то ни было выводить из-под старого директора, пока не выставим ему флаг инверсии цвета.

Если рёбер не осталось — перед нами двудольный граф, такого по условию не бывает.

(такая структура данных, только без флага инверсии, называется, «система непересекающихся множеств»).

ТЕОРИЯ. Начиная от самых «маленьких» рёбер, начинаем раскрашивать вершины в разные цвета. Если в какой-то момент это не удалось (цвета уже одинаковые) — выводим это ребро как ответ. Если соединяются два раскрашенных «островка» (в нашей терминологии «фирмы») — возможно, один из островков придётся инвертировать, и надо наладить инверсию так, чтобы она не захватила весь островок (судя по цифре 105, от нас ожидают сложность N log N, а не N²). Поскольку соединение кусков графа рёбрами и подсчёт компонент связности — это самая настоящая система непересекающихся множеств, я попытался приделать к этой самой СнПМ раскраску, не повышающую общую сложность (амортизированные почти что O(1) за транзакцию).

Попробуй доказать самостоятельно, что данная система не зависит от того, в каком порядке оказались рёбра с одинаковым весом.

И кончайте на чужом буе в рай въезжать!
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
Я подумал, что граф всегда можно разбить на две множества так, чтобы вершины, соединенные максимальным ребром были в одном множестве, а остальные вершины в другом, то-есть ответом всегда будет максимальное ребро. Я протестировал свое решение в яндекс.контест и получил ошибку на 8 тесте. Подскажите пожалуйста, что я не правильно понял из условия?
Может есть контрпример?

Контрпример: квадрат, верхнее ребро -- 2, боковые -- 1, нижнее -- 0. В терминах входных данных для задачи:
4 4
0 1 2
1 2 1
2 3 0
3 0 1

Если разбивать твоим алгоритмом, то в одно множество попадают две верхние вершины, во второе -- две нижние. Тогда "ребро минимального веса, соединяющее вершины из одного множества" -- это ребро соединяющее две нижние вершины (2 3), его вес -- 0.
Но если разбить граф на две левые вершины (3 0) и две правые (1 2), то "ребро минимального веса, соединяющее вершины из одного множества" имеет вес 1, что лучше, чем 0.
Ответ написан
Комментировать
longclaps
@longclaps
Ты вот в чем ошибся: максимальное ребро могло быть мостом, и выкусив его, ты развалил бы граф на минимум два подграфа, плюс пара инцидентных ребру першин будет третьим подграфом - а это перебор.
Поэтому просто перебери рёбра в порядке убывания, какое не окажется мостом - то и будет решением.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы