Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Задача "Таинство суммы" 
V
    Опции темы
Lacoste1024
Дата 3.1.2012, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 20.3.2011

Репутация: нет
Всего: 1



Решаю задачу. Ссылка на задачу. Пробую решить 2мя способами. 1й - перебор всех вариантов и сравнение + фильтр. 2й - бинарный поиск. 1й способ проходит 9 тестов (их содержание не знаю), а на 10й тестирующая программа говорит о превышении лимита времени. 2м способом решается только 2 теста, а на 3й выдаётся неправильный ответ. Что исправить? В каком направлении грести?
1й способ (перебор)
Код

#include <iostream>
using namespace std;
const int MAX_N = 50001;
const int C = 10000;

int main()
{
    int a1[MAX_N], a2[MAX_N], N1, N2;
    bool res = false;

    cin >> N1; for (int i = 0; i < N1; i++) cin >> a1[i];
    cin >> N2; for (int i = 0; i < N2; i++) cin >> a2[i];

    if (a1[N1-1] + a2[0] < C) {
        cout << "NO";
        return 0;
    }

    for (int i = 0; i < N1; i++) {
        if (a1[i] + a2[0] < C) continue;
        if (a1[i] + a2[N2-1] > C) continue;
        for (int j = 0; j < N2; j++)
            if (a1[i] + a2[j] == C) {
                res = true;
                break; break;
            }
    }

    if (res) cout << "YES";
    else cout << "NO";

    return 0;
}


2й способ (бинарный поиск) 
Код

#include <iostream>
using namespace std;
const int MAX_N = 50001;

int bSearch(int a[], int key, int from, int to)
{
    int middle = (from+to)/2;
    if (a[middle] == key) return 1;
    else {
        if (to-from == 1) return 0;
        else if (a[middle] > key) bSearch(a, key, middle+1, to);
        else if (a[middle] < key) bSearch(a, key, from, middle-1);
    }
}

int main()
{
    int a1[MAX_N], a2[MAX_N], N1, N2;
    bool res = false;
    
    cin >> N1; for (int i = 0; i < N1; i++) cin >> a1[i];
    cin >> N2; for (int i = 0; i < N2; i++) cin >> a2[i];
    
    for (int i = 0; i < N1; i++) {
        if (a1[i] + a2[0] < 10000) continue;
        if (a1[i] + a2[N2-1] > 10000) continue;
        else {
            int key = 10000 - a1[i];
            if (bSearch(a2, key, 0, N2-1) == 1) {
                res = true;
                break;
            }
        }
    }

    if (res) cout << "YES";
    else cout << "NO";
    
    return 0;
}

PM MAIL   Вверх
sQu1rr
Дата 3.1.2012, 19:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Не знаю, что у вас неправильно, но если память не жалко (а там дается 16мб, что веселит), то потратьте вы жалкие 64кб на массив типа bool.
Перый лист отметит true в существующих индексах, по прохождению второго списка, от 10000 отнимаем число и проверяем стоит ли true для этого индекса (если это не превышает 32767 разумеется)
Смысл надеюсь поняли? smile

Или вам конкретно хотелось бы узнать свои ошибки?

Вот о чем я говорю, берет 256кб (видимо bool берет все же по 4 байта... очень подозрительно), проходить все тесты. Да, решение не оптимальное, но первое что пришло в голову, когда увидели 16мб  smile 
Код

#include <iostream>

const int N = 65536;
const int R = 10000;
const int P = 32768;
bool arr[N];

int main()
{
    int n, tmp;
    std::cin >> n;
    while(n--) {
        std::cin >> tmp;
        arr[tmp + P] = true;
    }
    std::cin >> n;
    while(n--) {
        std::cin >> tmp;
        tmp = R - tmp + P;
        if(tmp <= N && arr[tmp]) {
            std::cout << "YES" << std::endl;
            return 0;
        }
    }
    std::cout << "NO" << std::endl;
}


Это сообщение отредактировал(а) sQu1rr - 3.1.2012, 19:43
PM MAIL Skype GTalk   Вверх
feodorv
Дата 3.1.2012, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



У Вас как минимум пропадают результаты вызовов bSearch в функции bSearch же.
В результате из bSearch возвращается неизвестно что.
Нужно хотя бы
Код

return bSearch(...);


Добавлено через 2 минуты и 52 секунды
И тонкий намёк: отсортированы оба массива (хотя, может, и так проскочит).
От рекурсивной функции я бы отказался (хотя, опять же, и так сойдёт))))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 4.1.2012, 00:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(Lacoste1024 @  3.1.2012,  15:16 Найти цитируемый пост)
Пробую решить 2мя способами. 1й - перебор всех вариантов и сравнение + фильтр. 2й - бинарный поиск. 

Здесь вообще не нужен ни бинарный поиск, ни перебор всех вариантов. Задача решается за один проход.
Даже более того, если бы это были 2 списка из разных файлов, то и память не нужна бы была.
Здесь сложность что списки идут по очереди из stdin, и поэтому приходится запоминать 1 список в каком-то массиве.
массив лучше брать не статический, так как полагать что максисальный размер будет
Цитата(Lacoste1024 @  3.1.2012,  15:16 Найти цитируемый пост)
const int MAX_N = 50001;

неверно.
По условию
Цитата
1 ≤ Ni ≤ 50000

он может быть и больше, так как элементы могут быть равны. например 1,1,1,1,1,2,2,2,2,2,3,3,3,3,3, и так до 50000 smile 
членов будет гораздо больше чем 50000, ваш статический массив переполнится и произойдет крах программы.
Лучше всего заюзать что-нибудь из стл.

Код

#include <iostream>
#include <deque>
using namespace std;

const int target = 10000;

int main ()
{
    int n;

    // Запоминаем 1-ый список в деке.
    deque <int> list1; 
    cin >> n; 
    while (n --) 
    {
       int a; 
       cin >> a;
       list1.push_back (a);
    }

    // Второй список запоминать не будем, а считать будем на лету.    
    cin >> n; 
    int a1, a2; 
    int from_where = 3; // флаги. биты 0 и 1 откуда читать, первый список, или второй соответственно
    bool res = false;
    while (!res) 
    {
       if (from_where & 1) //читаем из 1-го списка
       {
          if (list1.size ()==0)
             break;
          a1 = list1.front ();
          list1.pop_front ();
       }
       if (from_where & 2) //читаем из 2-го списка
       {
          if (n==0)
             break;
          cin >> a2;
          n --;
       }
       int sum = a1 + a2;
       from_where = sum < target ? 1 : 2; // если сумма меньше нужной, то след. читаем из 1-го списка, иначе из 2-го
       res = sum == target;
    }

    cout << (res ? "YES" : "NO") << endl;
    return 0;
}


Повторюсь, если бы списки шли из разных файлов, то программа бы упростилась вообще до 2-3 строчек.


PM MAIL   Вверх
feodorv
Дата 4.1.2012, 01:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(volatile @  4.1.2012,  00:54 Найти цитируемый пост)
он может быть и больше, так как элементы могут быть равны. например 1,1,1,1,1,2,2,2,2,2,3,3,3,3,3, и так до 50000 

Эээ, нет. Условие 1 <= Ni <= 50000 ставится именно на число элементов в списке, а не на значение элемента в списке. Последнее же выглядит как –32768 <= элемент <= 32767. Поэтому
Цитата(Lacoste1024 @  3.1.2012,  15:16 Найти цитируемый пост)
const int MAX_N = 50001;

правильно (может, единичка лишняя, это не принципиально). Другое дело, что не всегда стоит доверять входным данным...

Цитата(volatile @  4.1.2012,  00:54 Найти цитируемый пост)
Задача решается за один проход.

А вот это как раз и есть следствие отсортированности двух массивов сразу  smile 
Но дайте человеку самому дойти до истины  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 4.1.2012, 02:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(feodorv @  4.1.2012,  01:46 Найти цитируемый пост)
Эээ, нет. Условие 1 <= Ni <= 50000 ставится именно на число элементов в списке, а не на значение элемента в списке. Последнее же выглядит как –32768 <= элемент <= 32767.

feodorv, да, действительно, немного не внимательно прочел условие, вы правы, 
Цитата(feodorv @  4.1.2012,  01:46 Найти цитируемый пост)
Поэтому
const int MAX_N = 50001;
правильно 

Ну правилльно, то оно правильно, но стоит ли объяснять преимущества динамических массивов перед жестко заданным статическим массивом в 50001 элементов.

Так что от стл отказываться не стоит даже в этом случае.

PM MAIL   Вверх
feodorv
Дата 4.1.2012, 02:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(volatile @  4.1.2012,  02:06 Найти цитируемый пост)
но стоит ли объяснять преимущества динамических массивов перед жестко заданным статическим массивом

В принципе, надо себя уже приучать к динамическим массивам. Просто в данном случае важнее само решение, нежели экономия стека.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
sQu1rr
Дата 4.1.2012, 03:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Цитата(volatile @  4.1.2012,  02:06 Найти цитируемый пост)
Ну правилльно, то оно правильно, но стоит ли объяснять преимущества динамических массивов перед жестко заданным статическим массивом в 50001 элементов.
Так что от стл отказываться не стоит даже в этом случае.


Преимущество в экономии памяти, но скорость доступа к ячейке уменьшается в разы
В таких алгоритмах важна скорость, тем более когда лимит памяти сверх нужного (16МБ)
СТЛ нужно использовать везде по возможности, если от него что-то требуется (в моем примере стл ну просто лишний, например), что самому писать и лень и глупо да и не стоит, с этим соглашусь.
PM MAIL Skype GTalk   Вверх
volatile
Дата 4.1.2012, 03:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(sQu1rr @  4.1.2012,  03:20 Найти цитируемый пост)
Преимущество в экономии памяти, но скорость доступа к ячейке уменьшается в разы


sQu1rr, не в разы. При переходе с простых массивов на стл, скорость если и уменьшается, то на очень небольшие проценты.
Чаще всего скорость вообще, не уменьшается, т.е. 1:1
Сказывается правильность библиотеки и оптимизация компилятора.
Проверено неоднократно.

PM MAIL   Вверх
sQu1rr
Дата 4.1.2012, 03:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Цитата(volatile @  4.1.2012,  03:41 Найти цитируемый пост)
При переходе с простых массивов на стл, скорость если и уменьшается, то на очень небольшие проценты.
Чаще всего скорость вообще, не уменьшается, т.е. 1:1

Нет, я ж не спорю, это смотря что выбрать, если вектор, то да, но, извините, чем он отличается от обычного массива, просто его местонахождение будет в стеке, что сыграет свою роль на скорости но настолько маленькую, что забудем. А под
Цитата(volatile @  4.1.2012,  02:06 Найти цитируемый пост)
 преимущества динамических массивов 

вы скорее имели ввиду чтото вроде std::set или map или даже лист сойдет.
Так вот
Если доступ к ячейке обычного массива или вектора константен O(1), то
скорость доступа к set или map O(logn), заметьте я ничего не придумываю, это написано в документации, а
найти нужный элемент в списке O(n) в худшем случает. Так вот.
Значит при массиве в 50000 элементов каждый поиск будет стоит для мапа или сета будет стоить 15 операций, а список в худшем случае обойдется во все 50000.
Используя вектор в стл получем константное время, но опять же, если использование ограничено созданием вектора и дуступе к его элементам, не вижу смысла в использовании стл, это
стоит лишних заголовков и символов. Только для общего стиля, как говорится )

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

Это сообщение отредактировал(а) sQu1rr - 4.1.2012, 03:59
PM MAIL Skype GTalk   Вверх
Lacoste1024
Дата 4.1.2012, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 20.3.2011

Репутация: нет
Всего: 1



Господа, я ещё маленький и не знаю стл((
sQu1rr, спасибо за решение. Оно прошло =)
PM MAIL   Вверх
volatile
Дата 4.1.2012, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



sQu1rr, 
Цитата(sQu1rr @  4.1.2012,  03:58 Найти цитируемый пост)
Если доступ к ячейке обычного массива или вектора константен O(1), то
скорость доступа к set или map O(logn), заметьте я ничего не придумываю, это написано в документации,

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

sQu1rr, спор ни о чем. Я не критикую ваше решение, мне просто вчера захотелось решить эту задачку, вот и все. Не знаю даже почему. обычно здесь не очень интересные задачки, а здесь, вдруг захотелось smile . И вовсе не потому что ваше решение плохое.
Это разные решения. У вашего метода есть плюс - ему не нужен отсортированный список, но есть и минус, при расширении диапазона значений, решение станет невозможным, т.к. память начнет потребляться немеряно.

PM MAIL   Вверх
sQu1rr
Дата 4.1.2012, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Цитата(volatile @  4.1.2012,  10:41 Найти цитируемый пост)
sQu1rr, спор ни о чем. Я не критикую ваше решение, мне просто вчера захотелось решить эту задачку, вот и все. Не знаю даже почему. обычно здесь не очень интересные задачки, а здесь, вдруг захотелось  . И вовсе не потому что ваше решение плохое.
Это разные решения. У вашего метода есть плюс - ему не нужен отсортированный список, но есть и минус, при расширении диапазона значений, решение станет невозможным, т.к. память начнет потребляться немеряно.

Согласен, я уже признал это в предыдущем сообщении, извиняюсь за невнимательность  smile 
PM MAIL Skype GTalk   Вверх
feodorv
Дата 4.1.2012, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(Lacoste1024 @  4.1.2012,  08:51 Найти цитируемый пост)
sQu1rr, спасибо за решение. Оно прошло =) 

Вы хоть разобрались как оно работает? И почему так несправедливо проигнорировали лаконичное и изящное решение, предложенное volatile? Его стОит пристально изучить и переписать без использования stl, если stl вызывает затруднения. И поняли, что не так у Вас в решениях?

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

for (...) {
        ...
        for (...)
            if (...) {
                res = true;
                break; break;
            }
    }


Двойной break заставляет думать, что так автор хотел сразу выскочить из двойного цикла smile А в результате происходил практически полный перебор N1 * N2 вариантов. 

Это сообщение отредактировал(а) feodorv - 4.1.2012, 23:26


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Silent
Дата 12.1.2012, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 252
Регистрация: 3.10.2006

Репутация: нет
Всего: 9



Вставлю еще свои "пять копеек".
На АСМовских контестах предлагается решить ряд задач (10) за определенное время (3 часа). Эта задачка считается очень легкой и должна быть решена за 5-10 минут, сразу и без намека на отладку. Решение, предложенное volatile хорошее, быстрое, но не слишком ли "ненадежное"? (В том плане, что можно по неаккуратности ляп допустить) Для других исходных данных (допустим, N<200000), действительно необходимо линейное решение. А здесь прокатывает и O(NlogN):
Код

#include <iostream>
#include <map>
using namespace std;

int na, nb;

int main()
{
    map <int, int> a;
    scanf("%d",&na);
    int tmp;
    for (int i = 0; i < na; i++) 
    {
        scanf("%d",&tmp);
        a[tmp] = 1;
    }
    scanf("%d",&nb);
    bool flag = true;
    int i = 0;
    while ((i++ < nb) && (flag))
    {
        scanf("%d",&tmp);
        flag = (a[10000-tmp] != 1);
    }
    printf(flag ? "NO" : "YES");
    return 0;
}

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0688 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.