Организация номера 1 в 2d матрице - PullRequest
1 голос
/ 25 мая 2019

Учитывая количество строк и столбцов 2d матрицы

Изначально все элементы матрицы равны 0

Учитывая количество единиц, которые должны присутствовать в каждой строке

Учитывая количество единиц, которые должны присутствовать в каждом столбце

Определить, возможно ли сформировать такую ​​матрицу.

Пример:

Input: r=3 c=2 (no. of rows and columns)
2 1 0 (number of 1's that should be present in each row respectively)
1 2 (number of 1's that should be present in each column respectively)

Вывод: возможно

Объяснение:

1 1
0 1
0 0

Я пытался решить эту проблему в течение примерно 12 часов, проверяя, суммируется ли Ri = сумма Ci

Но я удивлялся, если это будет невозможнодля таких случаев, как

3 3
1 3 0
0 2 2

r и c могут быть до 10 ^ 5

Есть идеи, как мне двигаться дальше?

Редактировать: добавлены ограничения и вывод должен быть только«возможно» или «невозможно».Возможная матрица не должна отображаться.

Кто-нибудь может мне сейчас помочь?

Ответы [ 6 ]

2 голосов
/ 30 мая 2019

Я проиллюстрирую алгоритм на примере.

Предположим, у нас есть m строк и n столбцов.Пусть rows[i] будет номером 1 в строке i для 0 <= i < m, а cols[j] будет номером 1 в столбце j для 0 <= j < n.

Например, дляm = 3 и n = 4, мы могли бы иметь: rows = {4 2 3}, cols = {1 3 2 3}, и массив решений был бы:

    1 3 2 3
  +--------
4 | 1 1 1 1
2 | 0 1 0 1
3 | 0 1 1 1

Поскольку мы хотим знать только, существует ли решение, значенияв rows и cols могут быть переставлены в любом порядке.Решением каждой перестановки является просто перестановка строк и столбцов вышеприведенного решения.

Итак, с учетом rows и cols, сортировка cols по убыванию и rows по возрастаниюпорядок.Для нашего примера у нас есть cols = {3 3 2 1} и rows = {2 3 4} и эквивалентная проблема.

    3 3 2 1
  +--------
2 | 1 1 0 0
3 | 1 1 1 0
4 | 1 1 1 1

Мы преобразуем cols в форму, которая лучше подходит для алгоритма.Что нам говорит cols, так это то, что у нас есть две серии единиц длины 3, одна серия единиц длины 2 и одна серия единиц длины 1, которые должны быть распределены по строкам массива.Мы переписываем cols, чтобы захватить только это, то есть COLS = {2/3 1/2 1/1}, 2 серии длины 3, 1 серия длины 2 и 1 серия длины 1.

Поскольку у нас есть 2 серии длины 3,решение существует, только если мы можем поставить две 1 в первом ряду.Это возможно, потому что rows[0] = 2.На самом деле мы не ставим 1 в первый ряд, а записываем тот факт, что 1-е место было помещено, уменьшая длину ряда на длину 3. Таким образом, COLS становится:

COLS = {2/2 1/2 1/1}

, и мыскомбинируем два числа для серии длины 2, получив:

COLS = {3/2 1/1}

Теперь у нас есть уменьшенная задача:

3 | 1 1 1 0
4 | 1 1 1 1

Снова нам нужно поместить 1 из нашей серии длины 2 весть решение.К счастью, rows[1] = 3 и мы можем это сделать.Мы уменьшаем длину 3/2 и получаем:

COLS = {3/1 1/1} = {4/1}

У нас есть уменьшенная задача:

4 | 1 1 1 1

, которая решается 4 сериями длины 1, как раз то, что мы оставили,Если на каком-либо шаге ряд в COLS не может быть использован для удовлетворения количества строк, то решение невозможно.

Общая обработка каждой строки может быть сформулирована следующим образом.Для каждой строки r, начиная с первого элемента в COLS, уменьшите длину стольких элементов count[k]/length[k], сколько необходимо COLS, чтобы сумма count[k] равнялась rows[r].Исключить серии длины 0 в COLS и объединить серии одинаковой длины.

Обратите внимание, что поскольку элементы COLS расположены в порядке убывания длины, длина последнего уменьшенного элемента всегда меньше или равнак следующему элементу в COLS (если есть следующий элемент).

ПРИМЕР 2: Решение существует.

rows = {1 3 3}, cols = {2 2 2 1} => COLS = {3/2 1/1}

1 серия длины 2 уменьшена для удовлетворения rows[0] = 1, а 2 другие серии длины 2 остаются на длине 2.

rows[0] = 1
COLS = {2/2 1/1 1/1} = {2/2 2/1}

2 серии длины 2 уменьшаются, а 1 серии длины 1. Серия, длина которой стала 0, удаляется.и объединяются серии длины 1.

rows[1] = 3
COLS = {2/1 1/0 1/1} = {2/1 1/1} = {3/1}

Решение существует для rows[2]. Можно удовлетворить.

rows[2] = 3
COLS = {3/0} = {}

ПРИМЕР 3: Решение не существует.

rows = {0 2 3}, cols = {3 2 0 0} => COLS = {1/3 1/2}

rows[0] = 0
COLS = {1/3 1/2}

rows[1] = 2
COLS = {1/2 1/1}

rows[2] = 3  => impossible to satisfy; no solution.

ПРОСТРАНСТВЕННАЯ СЛОЖНОСТЬ

Легко видеть, что это O(m + n).

СЛОЖНОСТЬ ВРЕМЕНИ

Мы повторяем по каждой строке только один раз.Для каждой строки i нам нужно перебрать не более rows[i] <= n элементов COLS.Временная сложность составляет O(m x n).

Найдя этот алгоритм, я нашел следующую теорему:

Теорема Гавела-Хакими (Havel 1955, Hakimi 1962) утверждает, что существует матрица X n, m из 0 и 1 с итоговыми значениями строки a 0 = (a 1 , a 2 ,…, a n ) и итоги столбца b 0 = (b 1 , b 2 ,…, b m ) так, что b i ≥ b i + 1 для каждого 0 n − 1, m из 0 и 1 с итоговыми значениями строки a 1 = (a 2 , a 3 , …, A n ) и итоги столбца b 1 = (b 1 -1, b 2 -1,…, b a1 -1, b a1 + 1 ,…, b m ) также существует.

из поста Поиск существования бинарной матрицы по сумме строк и столбцов .

Это в основном то, что делает мой алгоритм, пытаясь оптимизировать убывающую часть, то есть все -1 в приведенной выше теореме. Теперь, когда я вижу приведенную выше теорему, я знаю, что мой алгоритм правильный. Тем не менее я проверил правильность своего алгоритма, сравнив его с алгоритмом грубой силы для массивов до 50 ячеек.

Вот реализация C #.

public class Pair
{
    public int Count;
    public int Length;
}

public class PairsList
{
    public LinkedList<Pair> Pairs;
    public int TotalCount;
}

class Program
{

    static void Main(string[] args)
    {
        int[] rows = new int[] { 0, 0, 1, 1, 2, 2 };
        int[] cols = new int[] { 2, 2, 0 };
        bool success = Solve(cols, rows);
    }

    static bool Solve(int[] cols, int[] rows)
    {
        PairsList pairs = new PairsList() { Pairs = new LinkedList<Pair>(), TotalCount = 0 };

        FillAllPairs(pairs, cols);

        for (int r = 0; r < rows.Length; r++)
        {
            if (rows[r] > 0)
            {
                if (pairs.TotalCount < rows[r])
                    return false;

                if (pairs.Pairs.First != null && pairs.Pairs.First.Value.Length > rows.Length - r)
                    return false;

                DecrementPairs(pairs, rows[r]);
            }
        }

        return pairs.Pairs.Count == 0 || pairs.Pairs.Count == 1 && pairs.Pairs.First.Value.Length == 0;
    }

    static void DecrementPairs(PairsList pairs, int count)
    {
        LinkedListNode<Pair> pair = pairs.Pairs.First;

        while (count > 0 && pair != null)
        {
            LinkedListNode<Pair> next = pair.Next;

            if (pair.Value.Count == count)
            {
                pair.Value.Length--;
                if (pair.Value.Length == 0)
                {
                    pairs.Pairs.Remove(pair);
                    pairs.TotalCount -= count;
                }
                else if (pair.Next != null && pair.Next.Value.Length == pair.Value.Length)
                {
                    pair.Value.Count += pair.Next.Value.Count;
                    pairs.Pairs.Remove(pair.Next);
                    next = pair;
                }
                count = 0;
            }
            else if (pair.Value.Count < count)
            {
                count -= pair.Value.Count;
                pair.Value.Length--;
                if (pair.Value.Length == 0)
                {
                    pairs.Pairs.Remove(pair);
                    pairs.TotalCount -= pair.Value.Count;
                }
                else if(pair.Next != null && pair.Next.Value.Length == pair.Value.Length)
                {
                    pair.Value.Count += pair.Next.Value.Count;
                    pairs.Pairs.Remove(pair.Next);
                    next = pair;
                }
            }
            else // pair.Value.Count > count
            {
                Pair p = new Pair() { Count = count, Length = pair.Value.Length - 1 };
                pair.Value.Count -= count;
                if (p.Length > 0)
                {
                    if (pair.Next != null && pair.Next.Value.Length == p.Length)
                        pair.Next.Value.Count += p.Count;
                    else
                        pairs.Pairs.AddAfter(pair, p);
                }
                else
                    pairs.TotalCount -= count;
                count = 0;
            }

            pair = next;
        }
    }

    static int FillAllPairs(PairsList pairs, int[] cols)
    {
        List<Pair> newPairs = new List<Pair>();

        int c = 0;
        while (c < cols.Length && cols[c] > 0)
        {
            int k = c++;
            if (cols[k] > 0)
                pairs.TotalCount++;
            while (c < cols.Length && cols[c] == cols[k])
            {
                if (cols[k] > 0) pairs.TotalCount++;
                c++;
            }
            newPairs.Add(new Pair() { Count = c - k, Length = cols[k] });
        }

        LinkedListNode<Pair> pair = pairs.Pairs.First;

        foreach (Pair p in newPairs)
        {
            while (pair != null && p.Length < pair.Value.Length)
                pair = pair.Next;

            if (pair == null)
            {
                pairs.Pairs.AddLast(p);
            }
            else if (p.Length == pair.Value.Length)
            {
                pair.Value.Count += p.Count;
                pair = pair.Next;
            }
            else // p.Length > pair.Value.Length
            {
                pairs.Pairs.AddBefore(pair, p);
            }
        }

        return c;
    }
}
2 голосов
/ 26 мая 2019

Подсказка: в одном из возможных решений используется проблема максимального потока путем создания специального графика и запуска на нем стандартного алгоритма максимального потока.

Если вы не знакомы с вышеуказанной проблемой, вы можете начать читать о нейнапример, здесь https://en.wikipedia.org/wiki/Maximum_flow_problem

Если вы заинтересованы в полном решении, пожалуйста, прокомментируйте, и я обновлю ответ.Но это требует понимания вышеупомянутого алгоритма.

Решение в соответствии с запросом:

Создайте график из r+c+2 узлов.

Узел 0 является источником, узел r+c+1 является приемником.Узлы 1..r представляют строки, а r+1..r+c столбцы.

Создайте следующие ребра:

  • от источника к узлам i=1..r емкости r_i
  • от узлов i=r+1..r+c до приемника емкости c_i
  • между всеми узлами i=1..r и j=r+1..r+c емкости 1

Запуск алгоритма максимального потока, насыщенныйребра между узлами строк и узлов столбцов определяют, куда вы должны поместить 1.

Или, если это невозможно, то максимальное значение потока меньше числа ожидаемых в матрице.

1 голос
/ 26 мая 2019

(Примечание: чтобы избежать путаницы между тем, когда я говорю о фактических числах в задаче, и тем, когда я говорю о нулях в единицах матрицы, вместо этого я собираюсь заполнить матрицу пробеламии X. Это, очевидно, не меняет проблему.)

Некоторые наблюдения:

  • Если вы заполняете строку, и есть (например) один столбец, нуждающийся в 10чем больше X и другого столбца, нужно еще 5 X, тем лучше иногда , лучше поставить X в столбец "10" и сохранить столбец "5" на потом (потому что позже вы можете столкнуться с 5 строками).что каждый из них нуждается в 2 X), но вам никогда лучше поставить X в столбце "5" и сохранить столбец "10" на потом (потому что даже если вы позже столкнетесь с 10 строками, всенужен X, они не будут возражать, если они не все войдут в одну колонку).Таким образом, мы можем использовать несколько «жадный» алгоритм: всегда ставьте X в столбце, все еще требующем большинства X.(Конечно, нам нужно убедиться, что мы не будем жадно ставить X в один и тот же столбец несколько раз для одной и той же строки!)
  • Поскольку вам не нужно фактически выводить возможную матрицувсе строки взаимозаменяемы, а столбцы взаимозаменяемы;все, что имеет значение, это то, сколько строк все еще нуждается в 1 X, сколько еще нужно 2 X и т. д., и аналогично для столбцов.

Имея это в виду, вот один довольно простой подход:

  • (Оптимизация.) Сложите счетчики для всех строк, сложите счетчики для всех столбцов и верните «невозможно», если суммы не совпадают.
  • Создать массивдлины r + 1 и заполняет его количеством столбцов, нуждающихся в 1 X, сколько столбцов нужно 2 X и т. д. (Вы можете игнорировать любые столбцы, требующие 0 X).
  • (Оптимизация) Для эффективного доступа к массиву создайте стек / связанный список / и т. Д.индексов ненулевых элементов массива в порядке убывания (например, начиная с индекса r , если он ненулевой, затем индекса r -1, если он ненулевой и т. д.), так что выможет легко найти элементы, представляющие столбцы, в которые нужно вставить X.
  • (Оптимизация.) Чтобы помочь определить, когда строка не может быть удовлетворена, также запишите общее количество столбцов, необходимых любые X и запишите наибольшее количество X, необходимое для любой строки.Если первое меньше второго, вернуть «невозможно».
  • (Оптимизация.) Сортировать строки по количеству X, в котором они нуждаются.
  • Перебирать строки, начиная с одногонуждаются в наименьшем количестве X и заканчиваются тем, на котором нужно наибольшее количество X, и для каждого:
    • Обновите массив соответствующим образом.Например, если строке требуется 12 X, а массив выглядит как [..., 3, 8, 5], то вы обновите массив, чтобы он выглядел как [..., 3 + 7 = 10, 8+5-7 = 6, 5-5 = 0].Если невозможно обновить массив, потому что у вас закончились столбцы для ввода X, верните «невозможное».(Примечание: эта часть никогда не должна возвращать «невозможно», потому что мы ведем подсчет количества оставшихся столбцов и максимального количества столбцов, которое нам понадобится, поэтому уже возвращено «невозможно» невозможно"если это должно было произойти. Я упоминаю эту проверку только для ясности.)
    • Обновите стек / связанный список индексов ненулевых элементов массива.
    • Обновите общее количество нужных столбцов любой X.Если теперь оно меньше, чем наибольшее число X, необходимое для любой строки, верните «невозможно».
    • (Оптимизация.) Если первый ненулевой элемент массива имеет индекс, превышающий количество оставшихся строк, вернуть «невозможно»".
  • Если мы завершим нашу итерацию, не вернув« невозможно », вернем« возможно ».

(Примечание: причина, по которой я говорю, чтобы начать со строки, нуждающейся в наименьшем количестве X, и перейти к строке с наибольшим количеством X, заключается в том, что в строке, требующей больше X, может потребоваться проверка обновления большего количества элементов массива и стека,поэтому строки, для которых требуется меньше X, дешевле. Это не просто вопрос откладывания работы: строки, для которых требуется меньше X, могут помочь «консолидировать» массив, так что будет меньше отдельных столбцов, что сделает более поздние строки более дешевыми.чем они были бы в противном случае. В сценарии с очень плохим случаем, например, в случае квадратной матрицы, где каждая строка требует отдельного положительного числа X, а каждый столбец нуждается в отдельном положительном числе X, наименьшее-мост порядка означает, что вы можете обрабатывать каждую строку за O (1) времени, для общего линейного времени, в то время как порядок "наименьший-наименьший" будет означать, что каждая строка будет занимать время, пропорциональное количеству X, в котором оно нуждается, для квадратичного времени в целом.)

В целом, это занимает не хуже, чем O ( r + c + n ) время (где n - количество X);Я думаю, что перечисленных оптимизаций достаточно, чтобы убедиться, что они ближе к O ( r + c ), но на 100% трудно быть уверенным.Я рекомендую попробовать, чтобы увидеть, достаточно ли это быстро для ваших целей.

0 голосов
/ 04 июня 2019

Вдохновляясь решением, данным РобертБароном, я попытался построить новый алгоритм.

rows = [int(x)for x in input().split()]
cols = [int (ss) for ss in input().split()]
rows.sort()
cols.sort(reverse=True)
for i in range(len(rows)):
    for j in range(len(cols)):
        if(rows[i]!= 0 and cols[j]!=0):
            rows[i] = rows[i] - 1;
            cols[j]  =cols[j]-1;
print("rows: ",rows)
print("cols: ",cols)
#if there is any non zero value, print NO else print yes
flag = True
for i in range(len(rows)):
    if(rows[i]!=0):
        flag = False
        break

for j in range(len(cols)):
    if(cols[j]!=0):
        flag = False

if(flag):
    print("YES")
else:
    print("NO")

здесь я отсортировал строки в порядке возрастания и столбцы в порядке убывания.позже уменьшая конкретную строку и столбец, если нужно разместить 1!это работает для всех тестов, размещенных здесь!остальное БОГ знает

0 голосов
/ 04 июня 2019

Эта проблема может быть решена в O (n log n) с помощью Теорема Гейла-Райзера .(где n - максимальная длина двух последовательностей градусов).

Сначала сделайте обе последовательности равной длины, добавив 0 к меньшей последовательности, и пусть эта длина будет n.Пусть последовательности A и B. Сортируйте A в неубывающем порядке, и сортируйте B в неубывающем порядке.Создайте еще один массив сумм префиксов P для B так, чтобы i-й элемент P был равен сумме первых i-х элементов B. Теперь переберите k от 1 до n и проверьте на
Gale-Ryser Theorem

Вторую сумму можно вычислить в O (log n), используя двоичный поиск индекса последнего числа в B, меньшего, чем k, а затем используя предварительно вычисленный P.

0 голосов
/ 26 мая 2019

Вы можете использовать грубую силу (перебирая все 2^(r * c) возможности), чтобы решить ее, но это займет много времени. Если r * c меньше 64, вы можете в некоторой степени ускорить его, используя побитовые операции над 64-битными целыми числами; однако даже в этом случае для перебора всех 64-битных возможностей (1 попытка в мс) потребуется более 500 миллионов лет.

Более разумный выбор - добавлять биты один за другим и продолжать размещать биты только в том случае, если нет ограничений. Это исключит подавляющее большинство возможностей, значительно ускоряя процесс. Посмотрите backtracking для общей идеи. Это мало чем отличается от решения судоку с помощью догадок: как только становится очевидно, что ваше предположение неверно, вы стираете его и пытаетесь угадать другую цифру.

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

Если будет включено более 50% битов, вы можете вместо этого работать над дополнительной проблемой (преобразовать все единицы в нули и наоборот, обновляя количество строк и столбцов). Обе проблемы эквивалентны, потому что любой ответ для одного также действителен для дополнительного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...