Я написал код для решения онлайн-проблемы, Вот.
mustConstraint = set()
notConstraint = set()
violated = 0
satisfied = 0
for i in range(0, int(input(''))):
constraint = input('')
mustConstraint.add(frozenset(constraint.split()))
for i in range(0, int(input(''))):
constraint = input('')
notConstraint.add(frozenset(constraint.split()))
for i in range(0, int(input(''))):
group = input('')
group = set(group.split())
for x in mustConstraint:
if x & group == x:
satisfied +=1
for y in notConstraint:
if y & group == y:
violated += 1
violated += len(mustConstraint) - satisfied
print(violated)
Подводя итог проблемы, первая строка входных данных содержит положительное целое число X с X => 0. Следующие X строк входных данных будут содержать два слова, разделенных пробелами. Эти два слова должны быть в одной группе. следующая строка ввода будет содержать еще одно положительное целое число Y, где Y => 0. Следующие строки ввода Y будут содержать два слова, разделенные пробелом. эти два слова не должны быть в одной группе. следующая строка входных данных будет содержать целое положительное число G с G >= 1. Каждая следующая строка входных данных G будет состоять из трех разных слов, разделенных одинарными пробелами. Эти три слова были помещены в одну группу.
Выведите целое число от 0 до X+Y — количество нарушенных ограничений.
Я настоятельно рекомендую вам посетить проблемный сайт здесь, так как проблему гораздо легче понять с помощью предоставленных примеров случаев и их пояснений.
К сожалению, поскольку последняя партия содержит около 300 000 входных данных, мои вложенные циклы for работают слишком медленно и не укладываются в 4-секундный лимит. Может ли кто-нибудь помочь мне оптимизировать мой код?
Большая часть задержки происходит из-за этого блока:
for i in range(0, int(input(''))):
group = input('')
group = set(group.split())
for x in mustConstraint:
if x & group == x:
satisfied +=1
for y in notConstraint:
if y & group == y:
violated += 1
вложенные циклы for выполняют 100 000 ^ 2 итерации каждый, что в общей сложности составляет 20 миллиардов итераций из этого блока кода (2 * 100 000 ^ 2)
если бы кто-то мог найти способ сократить количество итераций, это имело бы существенное значение.
Я не понимаю, что делают все int(input(''))
— вы используете их как заполнитель для чего-то другого? пожалуйста, объясните полностью.
@Vin Первая строка ввода — это количество строк имен. Итак, for i in range(0, int(input(''))):
читает количество строк, затем читает это количество строк.
Я не занимаюсь соревновательным программированием, но я бы сказал, что решение для многих входных данных связано с разработкой алгоритма, а не с его реализацией. Вы могли бы написать свой код на ASM, мне кажется, ваше решение слишком наивно; это источник проблемы с производительностью.
Самая очевидная оптимизация — заменить x & group == x
на x.issubset(y)
. issubset()
можно использовать короткое замыкание, чтобы большие наборы не были такими медленными.
Я вижу, что вы приняли ответы здесь и в своем предыдущем вопросе. Пожалуйста, не забудьте исправить оба вопроса, как указано в их комментариях (в данном случае первый комментарий @Barmar). Помните, что вопросы и ответы здесь должны быть полезны всем, включая будущих посетителей с такими же/похожими проблемами. (На самом деле мне не следовало отвечать здесь до того, как вы это исправили, я просто слишком устал, чтобы заметить это сам, и прочитал комментарии только потом.)
@nocomment Исправлено, спасибо за отзыв!
Спасибо. Хотя, как вы сами сказали: «проблему гораздо легче понять с помощью приведенных примеров случаев и их пояснений». Поэтому лучше приведите пример случая + объяснение. Я бы даже придумал свой, так как сайт мне не нравится. Например, поместить Бэтмена и Робина в список «обязательных», а Бэтмена и Джокера — в список «нельзя». Гораздо лучше, чем бессмысленные названия сайта.
Вы можете использовать операции над множествами более эффективно:
Для повышения эффективности читайте все входные данные одновременно.
Используйте словари для хранения ограничений и наборов для представления групп.
Эффективно проверяйте ограничения, перебирая каждую группу и обновляя счетчик нарушений.
Так:
import sys
input = sys.stdin.read
data = input().splitlines()
index = 0
# Read must constraints
must_constraint_count = int(data[index])
index += 1
must_constraints = []
for _ in range(must_constraint_count):
must_constraints.append(set(data[index].split()))
index += 1
# Read not constraints
not_constraint_count = int(data[index])
index += 1
not_constraints = []
for _ in range(not_constraint_count):
not_constraints.append(set(data[index].split()))
index += 1
# Read groups
group_count = int(data[index])
index += 1
groups = []
for _ in range(group_count):
groups.append(set(data[index].split()))
index += 1
# Check constraints
satisfied = 0
violated = 0
# Check must constraints
for must in must_constraints:
in_same_group = False
for group in groups:
if must.issubset(group):
satisfied += 1
in_same_group = True
break
if not in_same_group:
violated += 1
# Check not constraints
for not_c in not_constraints:
for group in groups:
if not_c.issubset(group):
violated += 1
break
print(violated)
Обработка ввода: для повышения эффективности весь ввод считывается одновременно с использованием sys.stdin.read.
Хранение ограничений. Ограничения хранятся в списках наборов для удобства проверки.
Группы обработки: группы хранятся в виде наборов, что позволяет использовать быструю проверку подмножества.
Проверка ограничений:
Для каждого обязательного ограничения проверьте, не является ли набор ограничений подмножеством какой-либо группы. Если да, то он удовлетворен. Если нет, то оно нарушено.
Для каждого не-ограничения проверьте, является ли набор ограничений подмножеством какой-либо группы. Если да, то оно нарушено.
Производительность:
Использование множеств и метода issubset() делает проверку ограничений эффективной.
Чтение всех входных данных одновременно и их обработка в памяти позволяет избежать множественных операций ввода-вывода, что ускоряет выполнение.
Дополнительную помощь по сложным общим операциям можно найти в Шпаргалке Big-O.
Кроме того, Временная сложность Python очень хорошо объясняет характеристики производительности встроенных типов данных Python.
«Это уменьшает количество итераций» — Так ли это? Как же так? - "и значительно улучшает производительность" - Так ли это? Сколько?
Насколько я могу судить, ответьте на оба моих вопроса: Нет, это не так. Представленный на сайте, он терпит неудачу при первом большом тестовом примере, как и код ОП. Как и ожидалось.
Ответ отличный, и это явные улучшения, но он все еще не соответствует временному ограничению в 4 секунды. Спасибо за ваш отзыв!
Спасибо за ответ! Правки помогли разобраться, спасибо за вашу помощь; не было кнопки слияния, которую можно было бы нажать, я новичок в этом пользовательском интерфейсе, я отредактировал оригинал.
Все еще примерно так же неэффективен, как и раньше, и по-прежнему не проходит первый большой тестовый пример.
Два решения, оба легко проходят все тесты.
Замените большие внутренние петли крошечными петлями над тремя парами группы, т. е. измените
for x in mustConstraint:
if x & group == x:
satisfied +=1
for y in notConstraint:
if y & group == y:
violated += 1
к этому:
a, b, c = group
for pair in {a, b}, {a, c}, {b, c}:
if pair in mustConstraint:
satisfied += 1
if pair in notConstraint:
violated += 1
Все три раздела определяют набор пар. Помогает поместить это в функцию. Затем найдите/подсчитайте нарушения:
from itertools import combinations
def pairs():
return {
frozenset(pair)
for _ in range(int(input()))
for pair in combinations(input().split(), 2)
}
must = pairs()
must_not = pairs()
are = pairs()
print(len(must - are) + len(must_not & are))
Пожалуйста, опишите здесь, что делает код, а не просто ссылку на внешний сайт. И результаты должны быть опубликованы в виде текста, а не скриншотов.