Даны N целых чисел X1, X2, ..., XN. Расставить между ними знаки "+" и "-" так, чтобы...

0 голосов
142 просмотров

Даны N целых чисел X1, X2, ..., XN. Расставить между ними знаки "+" и "-" так, чтобы значение получившегося выражения было равно заданному целому S.
В первой строке находятся числа N и S. В следующей строке - N чисел через пробел. 2 <= N <= 24, 0 <= Xi <= 50 000 000, -1 000 000 000 <= S <= 1 000 000 000.<br> Если получить требуемый результат невозможно, вывести "No solution", если можно, то вывести равенство. Если решение не единственное, вывести любое.

Пример
входные данные:
3 13
7 3 9
выходные данные:
7-3+9=13

Ограничение по времени: 1 сек,
Ограничение по памяти: 64 мегабайта,
Язык программирования: PascalABC.NET.


Информатика (3.7k баллов) | 142 просмотров
0

Неужели никто не поможет?)) Хотя бы без ограничения по времени сделайте:(

Дан 1 ответ
0 голосов
Правильный ответ

Ниже запрограммировано примерно следующее: делим массив на 2 части (в каждой будет не больше 12 элементов), для каждой части вычисляем всевозможные суммы с плюсами-минусами. Затем для каждой суммы из левой части пытаемся найти бинпоиском сумму из правой части, чтобы получилось то, что надо. Если нашли - повторяем всё для каждой части и пытаемся восстановить ответ.

function getAllSums(myarr: array of integer): array of integer;
begin
  var answer := arrFill(round(power(2, myarr.Length)), 0);
  for var i := 0 to round(power(2, myarr.Length)) - 1 do
  begin
    var s := 0;
    var k := i;
    for var j := 0 to myarr.Length - 1 do
    begin
      if k mod 2 = 0 then s += myarr[j] else s -= myarr[j];
      k := k div 2;
    end;
    answer[i] := s;
  end;
  result := answer;
end;
 
function getSolution(myarr: array of integer; s: integer): array of boolean;
begin
  if myarr.Length = 1 then
  begin
    result := Arr(myarr[0] = s);
    exit;
  end;
  var sums_left := getAllSums(myarr[:myarr.Length div 2]);
  var sums_right := getAllSums(myarr[myarr.Length div 2:]).Sorted.ToArray;
  for var i := 0 to sums_left.Length - 1 do
    if sums_right.BinarySearch(s - sums_left[i]) >= 0 then
    begin
      result := getSolution(myarr[:myarr.Length div 2], sums_left[i]) +
      getSolution(myarr[myarr.Length div 2:], s - sums_left[i]);
      exit;
    end;
  result := new boolean[0];
end;
 
begin
  var n := readinteger;
  var s := readinteger;
  var xn := readarrinteger(n).Select(x->abs(x)).ToArray;
  var signs := getSolution(xn, s);
  if signs.Length = 0 then
    print('No solution')
  else 
  begin
    if signs[0] then 
      write(xn[0])
    else
      write('-', xn[0]);
    for var i := 1 to xn.Length - 1 do
      if signs[i] then 
        write('+', xn[i])
      else
        write('-', xn[i]);
    write('=', s);
  end;
end.

(148k баллов)
0

У меня на полудохлом нетбуке за (максимально) 35 мс работает для массива из 24 элементов, в 1 секунду вроде должно вписываться)

0

Это я максимум пишу, в среднем за 1000 случайных тестов 12,859.

0

Если убрать ввод-вывод тормозящий, будет меньше.

0

1. Программа при N = 24 с отключенным debug и с выводом по shift-f9 у меня работает 2 мс.

0

2. Нашелся источник задачи. Это книжка 2006 (или даже раньше?) года по олимпиадному программированию. Удивительно, что авторы рассказывают там алгоритм перебора за 2^N и не рассказывают за N 2^(N/2). Притом в разборе акцент делают на том, что пересчитывать сумму каждый раз очень долго