Матч 410, Добавить провода (AddElectricalWires)

Дивизион 2, Уровень 2; Дивизион 1, Уровень 1

 

У Вас дома имеется электрическая цепь, представленная в виде графа. Ребрами графа являются провода, а вершинами – точки их соединения. Любая пара вершин соединена не более чем одним проводом, никакая вершина не соединена сама с собой. Каждая вершина является либо розеткой, либо точкой подключения к наружной сети электропитания.

Массив wires описывает множество имеющихся проводов. Массив gridConnections описывает множество вершин, подключенных к наружной сети.

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

 

Класс: AddElectricalWires

Метод: int maxNewWires(vector<string> wires,

                       vector<int> gridConnections)

Ограничения: wires и gridConnections содержат от 1 до 50 элементов, wires[i][j] содержит ‘0’ или ‘1’, wires[i][i] = ‘0’, wires[i][j] = wires[j][i], все элементы gridConnections разные, никакая пара вершин из gridConnections не связана проводами (даже не напрямую).

 

Вход. Массив wires описывает множество имеющихся проводов. Массив gridConnections описывает множество вершин, подключенных к наружной сети.

 

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

 

Пример входа

wires

gridConnections

{"000","000","000"}

{0}

{"000","000","000"}

{0,1}

{"01000","10100","01010","00100","00000"}

{2,4}

 

Пример выхода

3

1

3

 

 

РЕШЕНИЕ

поиск в глубину

 

По массиву строк wires построим матрицу смежности графа m. Подсчитаем в переменной Edges общее количество имеющихся проводов (ребер графа): для этого следует подсчитать общее число единиц в массиве m и поделить его на 2 (каждое ребро будет подсчитано дважды, так как имеющийся граф является неориентированным).

Каждая вершина, подключенная к наружной сети, вместе в вершинами, связанными с ней (даже не напрямую), образуют отдельную компоненту связности. При помощи поиска в глубину выделим эти компоненты. Очевидно, что граф распадется на множество компонент, каждая из которых содержит одну вершину из gridConnections, а также останется некоторое множество вершин, не входящее ни в одну из компонент. Пусть последнее множество содержит LeftVertex вершин. Между вершинами, входящими в разные компоненты связности, провода протягивать нельзя, так как произойдет замыкание. Между двумя вершинами, входящими в одну компоненту, можно добавить провод, если только он не был между ними изначально. Между любыми двумя из оставшихся LeftVertex вершин можно добавить провод. Для максимизации общего числа проводов множество из LeftVertex вершин необходимо присоединить к той компоненте связности, которая имеет наибольшее число вершин. В переменной MaxConnComp будем вычислять величину наибольшей компоненты связности. При помощи глобальной переменной Vertex в функции dfs будем подсчитывать число вершин, входящих в текущую компоненту связности. Если текущая компонента связности содержит Vertex вершин, то максимум она может содержать Vertex * (Vertex – 1)/2 ребер (полный граф). В переменной res вычисляем наибольшее число ребер, которое может содержаться во всех компонентах, порожденных вершинами из gridConnections. Присоединяем проводами множество из  LeftVertex вершин к наибольшей компоненте связности: между LeftVertex вершинами можно провести LeftVertex * (LeftVertex – 1)/2 ребер, между LeftVertex вершинами множества оставшихся ребер и MaxConnComp вершинами из наибольшей компоненты связности можно провести MaxConnComp*LeftVertex ребер. Остается из общего числа ребер res вычесть количество уже имеющихся Edges, чтобы найти максимальное число проводов, которое можно добавить.

 

ПРОГРАММА

 

#include <cstdio>

#include <vector>

#include <string>

#include <memory>

using namespace std;

 

int n, Vertex, m[51][51], used[51];

 

void dfs(int v)

{

  int i;

  used[v] = 1; Vertex++;

  for(i = 0; i < n; i++)

    if (m[v][i] && !used[i]) dfs(i);

}

 

class AddElectricalWires

{

public:

  int maxNewWires(vector<string> wires, vector<int> gridConnections)

  {

    int i, j, res = 0, LeftVertex, Edges = 0, MaxConnComp = 0;

    memset(used,0,sizeof(used));

    LeftVertex = n = wires.size();

    for(i = 0; i < n; i++)

      for(j = 0; j < n; j++)

        if (m[i][j] = (wires[i][j] == '1')) Edges++;

    Edges /= 2; // graph is NOT oriented, every edge is counted twice

 

    for(i = 0; i < gridConnections.size(); i++)

    {

      Vertex = 0;

      dfs(gridConnections[i]);

      res += Vertex * (Vertex - 1) / 2;

      LeftVertex -= Vertex;

      MaxConnComp = max(MaxConnComp,Vertex);

    }

    res += LeftVertex * (LeftVertex - 1) / 2 + MaxConnComp * LeftVertex;

    return res - Edges;

  }

};