Форум программистов, компьютерный форум CyberForum.ru

Задача на динамику или комбинаторику - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.74
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
11.08.2011, 11:50     Задача на динамику или комбинаторику #1
Условие
Для заданных натуральных чисел N и K требуется вычислить количество чисел от 1 до N, имеющих в двоичной записи ровно K нулей. два натуральных числа через пробел N и K, не превышающие 10^9

На этой задаче мой решения не проходят по времени. Можно услышать ваше мнение по поводу решения этой задачи?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
11.08.2011, 15:39  [ТС]     Задача на динамику или комбинаторику #21
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Чисел 4 -ри, а не три!
Откуда 4?
Какое 4 число?
Ваша программа работает больше 30 секунд (до 30 я считал, а потом надоело )
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
-=ЮрА=-
Заблокирован
Автор FAQ
11.08.2011, 16:00     Задача на динамику или комбинаторику #22
Цитата Сообщение от Dani Посмотреть сообщение
1 - 1
2 - 10
3 - 11
4 - 100
5 - 101
6 - 110
7 - 111
8 - 1000
Имеющие в двоичной записи 1 нуль: 10, 110,101
Внимательно посчитай: 10, 100,101,110,1000 их даже 5 - за это тебе писал, чтобы ты сам обратил внимание что в 8 3 - 5 различных цифр с двоичной записью имеющей нолик. Просмотрев код понял забыл что вначале инициализировал счётчик -1 -цей поэтому вывело 4, их 5!Чтобы было интересно смотреть на экран вывожу анализируемую 2-ную запись взаголвке диалогового окна
C++
1
SetWindowText(hWnd,buf);
, скриншоты в работе и код ниже...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <windows.h>
#include <stdio.h>
#include <conio.h>
 
void PumpMessages(HWND hWND);
char * num2bin(unsigned long lnum);
 
int main()
{
    HWND hWnd = GetForegroundWindow();
    long N,K,nCount = 0;
    char str[19],*buf;
    do
    {
        printf("Enter numbers:\r\n");
        scanf("%[^\n]",str);
        sscanf(str,"%u %u",&N,&K);
        memset(str,'0',K);
        str[K] = '\0';
        while(0 < N)
        {
            if(strstr(buf = num2bin(N),str))
                nCount++;
            //printf("bin %s\r\n",buf);
            SetWindowText(hWnd,buf);
            N--;
            //Избегаем замерзания программы
            PumpMessages(hWnd);
        }
        printf("%d numbers with square 10^%u\r\n",nCount,K);
    }
    while(toupper(getch()) == 'Y');
    printf("Enter num: ");
    unsigned long lnum;scanf("%u",&lnum);
    printf("%s\r\n",num2bin(lnum));
    getch();
    return 0;
}
 
char * bin = (char *)malloc(sizeof(char));
char * num2bin(unsigned long lnum)
{
    int i = 0;
    do
    {
        bin[i] = '0';
        if(lnum%2)
            bin[i] = '1';
        lnum /= 2;
        if(0 < lnum)
            bin = (char *)realloc(bin,(1 + (i = i + 1))*sizeof(char));
    }
    while(0 < lnum);
    bin[i + 1] = '\0';
    return bin;
}
 
void PumpMessages(HWND hWND)
{
    MSG msg;
    // Handle dialog messages
    while(PeekMessage(&msg, hWND, 0, 0, PM_REMOVE))
        if(!IsDialogMessage(hWND, &msg) && TranslateMessage(&msg))
            DispatchMessage(&msg); 
}
PS: Твои 10000000 выводятся за 3-4 минуты работы, по другому нужна только формула для расчёта, слёту двоичных чисел с нулями и их выводом, всё равно за секунду ни одна программа на обычной машиене тебе не посчитает...
Миниатюры
Задача на динамику или комбинаторику   Задача на динамику или комбинаторику  
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
11.08.2011, 16:06  [ТС]     Задача на динамику или комбинаторику #23
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Внимательно посчитай: 10, 100,101,110,1000 их даже 5 - за это тебе писал, чтобы ты сам обратил внимание что в 8 3 - 5 различных цифр с двоичной записью имеющей нолик. Просмотрев код понял забыл что вначале инициализировал счётчик -1 -цей поэтому вывело 4, их 5!Чтобы было интересно смотреть на экран вывожу анализируемую 2-ную запись взаголвке диалогового окна
У них у всех k=1 нулей?
у 100 - два нуля, 1000 - 3, а надо 1. Потому что k=1!

Добавлено через 1 минуту
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
PS: Твои 10000000 выводятся за 3-4 минуты работы, по другому нужна только формула для расчёта, слёту двоичных чисел с нулями и их выводом, всё равно за секунду ни одна программа на обычной машиене тебе не посчитает...
Посчитает, только подход другой нужен - в этом я уверен.

Добавлено через 1 минуту
Если есть задача - найдется и решение
-=ЮрА=-
Заблокирован
Автор FAQ
11.08.2011, 16:09     Задача на динамику или комбинаторику #24
Цитата Сообщение от Dani Посмотреть сообщение
У них у всех k=1 нулей?
у 100 - два нуля, 1000 - 3, а надо 1. Потому что k=1!
Тогда цикл по N должен выглядеть вот так
C++
1
2
3
4
5
6
7
8
9
10
11
while(0 < N)
        {
            SetWindowText(hWnd,buf);
            if((buf = strstr(num2bin(N),str)))
            if(buf[1] != '0')
                nCount++;
            //printf("bin %s\r\n",buf);
            N--;
            //Избегаем замерзания программы
            PumpMessages(hWnd);
        }
выводит 3 в 8 1, ну на сим удачи тебе в поисках "хорошего" алгоритма...
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
11.08.2011, 16:27     Задача на динамику или комбинаторику #25
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
удачи тебе в поисках "хорошего" алгоритма...
Удача пригодилась =)
Таки я был прав, треугольник Паскаля рулит!
К сожалению, понятно объяснить вряд ли смогу, сам только сегодня его строить научился, но тем не менее код проходит все тесты практически мгновенно.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
int main(){
    
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    
    //строим треугольник паскаля
    int pas[33][33] = {};
    pas[0][0] = 1;
    for (int i = 0; i < 33; ++i)
    {
        pas[i][0] = 1;
        pas[i][i] = 1;
        for (int j = 1; j < i ; ++j)
        {
            pas[i][j] = pas[i-1][j-1] + pas[i-1][j];
        }
    }
    
    int n, k;
    std::cin >> n >> k;
    std::string bin;
    
    //переводим число в двоичное представление
    for ( ; n; n >>= 1)
        bin.push_back( (n & 1) + '0');
    
    //подсчитываем количество сочетаний (количество разрядов - 1) по k
    
    int result = 0;
    
    for (size_t i = k + 1; i < bin.size(); ++i)
    {
        result += pas[i-1][k];
    }
    
    //отдельно рассматриваем случай с последним разрядом...
    int zerocount = 0;
    for (int i = bin.size() - 2; i >= 0 && zerocount <= k; --i)
    {
        if (bin[i] == '1')
        {
            if (k - zerocount - 1 >= 0)
            {
                result += pas[i][k - zerocount - 1];
            }
        }
        else
            ++zerocount;
    }
 
    if (zerocount == k)
        ++result;
 
 
    std::cout << result << std::endl;       
}
mac_alleb
7 / 7 / 0
Регистрация: 05.08.2011
Сообщений: 54
11.08.2011, 18:28     Задача на динамику или комбинаторику #26
Набросал программку . Я так понял, главная задача: перевод большого натурального (хотя бы)
числа из десятичного представления в двоичное (хотя бы 32 бит). Моя функция c10to2 это и
делает, причем число бит и размер исходного числа для алгоритма не важны (в демо версии
упрощено до 200 бит). В Chislo1 необходимо ввести побайтно исходное число N. После работы
функций для решения задачи (пока частичного) можно посмотреть регистр BL. В нем будет
число нулевых битов в данном числе (К). Число упаковано в переменную Result в слошную цепочку
битов слева направо. Пока так . Если треба доделать задачу до конца, т.е. состряпать
интерфейсик и процедуру перебора чисел - не проблема, только сообщите .
Вложения
Тип файла: txt nulls.txt (1.9 Кб, 18 просмотров)
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
11.08.2011, 18:33     Задача на динамику или комбинаторику #27
Цитата Сообщение от mac_alleb Посмотреть сообщение
Набросал программку . Я так понял, главная задача: перевод большого натурального (хотя бы)
числа из десятичного представления в двоичное (хотя бы 32 бит). Моя функция c10to2 это и
делает, причем число бит и размер исходного числа для алгоритма не важны (в демо версии
упрощено до 200 бит). В Chislo1 необходимо ввести побайтно исходное число N. После работы
функций для решения задачи (пока частичного) можно посмотреть регистр BL. В нем будет
число нулевых битов в данном числе (К). Число упаковано в переменную Result в слошную цепочку
битов слева направо. Пока так . Если треба доделать задачу до конца, т.е. состряпать
интерфейсик и процедуру перебора чисел - не проблема, только сообщите .
Перевод числа в двоичную сс на с++ 2 строки занимает, соль не в нем, а в алгоритме.
У вас не получится за секунду перебрать и проверить все возможные числа.
Поэтому эта задача решается комбинаторикой и динамическим программированием.
И да, это сложная олимпиадная задача =)
mac_alleb
7 / 7 / 0
Регистрация: 05.08.2011
Сообщений: 54
15.08.2011, 00:06     Задача на динамику или комбинаторику #28
Покажите мне эти две строчки, да еще для числа произвольной длины . А что каксается задачи
для всех N не превышающих 10^9, то попробую на ассемблере уложится в секунду даже на двушке .
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
15.08.2011, 07:28     Задача на динамику или комбинаторику #29
Цитата Сообщение от mac_alleb Посмотреть сообщение
Покажите мне эти две строчки, да еще для числа произвольной длины
25-26 в моем коде.
Просто перебор до 10^9 полсекунды примерно занимает, а если еще и переводить каждый раз в двоичную сс и проверять строку, то по времени никак не уложитесь =)
mac_alleb
7 / 7 / 0
Регистрация: 05.08.2011
Сообщений: 54
15.08.2011, 09:29     Задача на динамику или комбинаторику #30
За ночку создал алгоритм обратного перевода из двоичной в десятичную для чисел 200-бит (демо
версия). Пришлось "идти" через 16-тиричную систему. Прога наполовину готова. Думаю еще день-два
и выложу. Что касается собственно задачи, то зачем каждый раз переводить в двоичку, можно перевести
один раз, а затем добавлять по 1. Вообще-то тут пахнет 64-битной арифметикой . Если нужны будут
арифметические процедуры для таких чисел сообщите .
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
15.08.2011, 10:09     Задача на динамику или комбинаторику #31
diagon прав. Не нужен здесь перебор.
Надо взять N и посмотреть, сколько битов оно занимает. Например, M битов. Тогда надо считать число сочетаний из M-1 по К. К нулей могут быть в любом порядке среди младших M-1 битов, так как старший бит должен быть 1.
А число сочетаний считается по треугольнику Паскаля.
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
15.08.2011, 10:30     Задача на динамику или комбинаторику #32
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Надо взять N и посмотреть, сколько битов оно занимает. Например, M битов. Тогда надо считать число сочетаний из M-1 по К. К нулей могут быть в любом порядке среди младших M-1 битов, так как старший бит должен быть 1.
Не совсем так, например N = 10001 в двоичной записи и K=2. Если брать все сочетания, то среди них будут
11100,
10110 и т.д.,
а эти числа уже превышают число N.

Добавлено через 12 минут
Этот метод подойдет, если суммировать сочетания
http://www.cyberforum.ru/cgi-bin/latex.cgi?<br />
1+C^K_{K+1} +...+C^K_{M-2} + D,

Вот D то как раз и надо ухитриться подсчитать, а D - все числа с K нулями, не превышающие числа N, и со старшим единичным битом на M-ой позиции
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
15.08.2011, 12:45  [ТС]     Задача на динамику или комбинаторику #33
Цитата Сообщение от diagon Посмотреть сообщение
Удача пригодилась =)
Таки я был прав, треугольник Паскаля рулит!
К сожалению, понятно объяснить вряд ли смогу, сам только сегодня его строить научился, но тем не менее код проходит все тесты практически мгновенно.
Проходит даже: http://www.cyberforum.ru/cgi-bin/latex.cgi?{10}^{19} 1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.08.2011, 05:57     Задача на динамику или комбинаторику
Еще ссылки по теме:

В какую область попадает точка, или задача для первокурсника C++
C++ Сложная задача или есть ли в C++ типы с порядком в 30 цифр?
Задача на комбинаторику C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
mac_alleb
7 / 7 / 0
Регистрация: 05.08.2011
Сообщений: 54
17.08.2011, 05:57     Задача на динамику или комбинаторику #34
Добил прогу . Выкладываю (рабочая версия, могут быть огрехи ). Как и ранее, числа запакованы
слева направо. В двоичных и 16-тиричных первый байт содержит фактическую длину числа. Вывод
К и времени в 16-тиричке, т.к. лень было доделывать вывод в 10-тичной.
Вложения
Тип файла: txt nulls.txt (8.5 Кб, 63 просмотров)
Yandex
Объявления
17.08.2011, 05:57     Задача на динамику или комбинаторику
Ответ Создать тему
Опции темы

Текущее время: 14:41. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru