Форум программистов, компьютерный форум, киберфорум
Haskell
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886

Подпоследовательности с одинаковыми суммами

31.05.2015, 02:40. Показов 2333. Ответов 26
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Условие задачи:
Есть N разных положительных целых чисел.
Требуется найти все пары последовательностей из этих чисел длинной не более M, такие что они будут иметь одинаковую сумму.

Решение:
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
data NodeList = NodeList 
    { nlRoot  :: [Int]
    , nlLength :: Int
    , nlSum    :: Int }
    deriving (Show)
 
makeSums :: [Int] -> Int -> [NodeList] -> [NodeList]
makeSums [] _  acc         = acc    
makeSums (x:xs) maxlen acc = makeSums xs maxlen $ addNodeList $ (++) acc $ map addNode $ filter lessLen acc
    where addNodeList y = (NodeList [x] 1 x) : y
          addNode (NodeList root len sum) = NodeList (x:root) (len+1) (sum+x) 
          lessLen y = nlLength y < maxlen
 
makePairs :: [NodeList] -> [([Int], [Int])] -> [([Int], [Int])]
makePairs [] acc     = acc
makePairs (x:xs) acc = makePairs xs $ (++) acc $ map pairNodes $ filter sameSum xs 
    where sameSum y = nlSum x == (nlSum y)
          pairNodes y = (nlRoot x, nlRoot y)
 
solve :: [Int] -> Int -> [([Int], [Int])]
solve nums maxlen = makePairs (makeSums nums maxlen []) []
    
main = do 
  print $ solve [1,2,3,4] 3
Вопросы:
1. Какие есть способы избежать конфликта имён в строках 2-4 с именами функций из текущего контекста?
2. Как лучше всего "упаковать" makeSums и makePairs во внутрь функции solve?
3. Как можно упростить и/или ускорить этот код (кроме использования хэш-таблицы в makePairs)?

Добавлено через 26 минут
4. Какой есть хороший способ засекать время выполнения функции?

Добавлено через 32 минуты
Haskell: Успешно time: 3.77 memory: 7624 signal:0
C#: Успешно time: 0.13 memory: 24264 signal:0
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
31.05.2015, 02:40
Ответы с готовыми решениями:

Номера строк с одинаковыми суммами
Здравствуйте! Подскажите, пожалуйста, код для выведения номеров всех строк с одинаковыми суммами и их суммы (в матрице). Например, дана...

Разбиение множества на подмножества с одинаковыми суммами
Здраствуйте. Есть такая задача: разбить последовательность чисел от 1 до n * n на n подмножеств так, чтобы все они состояли из n чисел и...

Вывести массив с одинаковыми суммами столбцов
программа вычисляет сумму столбцов массива. Пытаюсь вывести дополнительно одинаковые суммы столбцов отдельно если случайно выпадают, если...

26
202 / 200 / 65
Регистрация: 06.10.2013
Сообщений: 552
31.05.2015, 07:57
Цитата Сообщение от Shamil1 Посмотреть сообщение
1. Какие есть способы избежать конфликта имён в строках 2-4 с именами функций из текущего контекста?
Переименовать что-нибудь.

Цитата Сообщение от Shamil1 Посмотреть сообщение
2. Как лучше всего "упаковать" makeSums и makePairs во внутрь функции solve?
Через where или let...in

Цитата Сообщение от Shamil1 Посмотреть сообщение
4. Какой есть хороший способ засекать время выполнения функции?
Вот здесь достаточно подробно про профилирование.
2
Модератор
 Аватар для Curry
5158 / 3488 / 536
Регистрация: 01.06.2013
Сообщений: 7,568
Записей в блоге: 9
31.05.2015, 09:44
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Data.Time
import Data.List
import Data.Function
 
solve nums maxlen = nub $ concat $ concatMap (mkPair . map snd) $ filter noOne $
                    groupBy ((==) `on` fst) $ sortBy (compare `on` fst) $ 
                    map (\a -> (sum a,a)) $
                    filter ((<=maxlen).length) $ tail $ subsequences nums
    where noOne [x] = False
          noOne _ = True
          mkPair [x,y] = [[(x,y)]]
          mkPair (x:xs) = map ((,)x) xs : mkPair xs
          
main:: IO () 
main = do
       begT <- getCurrentTime
       print $ solve [1,2,3,4,5,6] 4
       endT <- getCurrentTime
       print $ diffUTCTime endT begT
Без nub результат тот же, но время ... больше.

Цитата Сообщение от Shamil1 Посмотреть сообщение
кроме использования хэш-таблицы
Тут бы скорее Data.Map (он же словарь) пригодился, по ключу равному суммам.
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
31.05.2015, 10:17
Цитата Сообщение от Shamil1 Посмотреть сообщение
Haskell: Успешно time: 3.77 memory: 7624 signal:0
C#: Успешно time: 0.13 memory: 24264 signal:0
F# Success time: 0.34s memory: 29936KB

Добавлено через 4 минуты
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Код Haskell
этот вариант ощутимо медленее чем у ТС http://ideone.com/iZCeWC
0
Модератор
 Аватар для Curry
5158 / 3488 / 536
Регистрация: 01.06.2013
Сообщений: 7,568
Записей в блоге: 9
31.05.2015, 11:46
Цитата Сообщение от pycture Посмотреть сообщение
этот вариант ощутимо медленее чем у ТС
Вообще то я не стремился к скорости, короче делал. Но, на моём компе вариант ТС для solve [1,2,3,4,5,6] 4 6 ms, а мой 3 ms. Впрочем, без использования нормальных контейнеров, на встроенных списках, Haskell и бабушка на ходунках обгонит.

Добавлено через 1 час 14 минут
Цитата Сообщение от pycture Посмотреть сообщение
F#
Кстати, у Вас совсем не то выдаёт.
0
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886
31.05.2015, 13:01  [ТС]
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Без nub результат тот же, но время ... больше.
У меня наоборот с nub медленней.
0
Модератор
 Аватар для Curry
5158 / 3488 / 536
Регистрация: 01.06.2013
Сообщений: 7,568
Записей в блоге: 9
31.05.2015, 13:30
Цитата Сообщение от Shamil1 Посмотреть сообщение
У меня наоборот с nub медленней
Может зависить от последовательности проверок.
Кликните здесь для просмотра всего текста
Haskell
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
import Data.Time
import Data.List
import Data.Function
 
data NodeList = NodeList 
    { nlRoot  :: [Int]
    , nlLength :: Int
    , nlSum    :: Int }
    deriving (Show)
 
makeSums :: [Int] -> Int -> [NodeList] -> [NodeList]
makeSums [] _  acc         = acc    
makeSums (x:xs) maxlen acc = makeSums xs maxlen $ addNodeList $ (++) acc $ map addNode $ filter lessLen acc
    where addNodeList y = (NodeList [x] 1 x) : y
          addNode (NodeList root len sum) = NodeList (x:root) (len+1) (sum+x) 
          lessLen y = nlLength y < maxlen
 
makePairs :: [NodeList] -> [([Int], [Int])] -> [([Int], [Int])]
makePairs [] acc     = acc
makePairs (x:xs) acc = makePairs xs $ (++) acc $ map pairNodes $ filter sameSum xs 
    where sameSum y = nlSum x == (nlSum y)
          pairNodes y = (nlRoot x, nlRoot y)
 
solve :: [Int] -> Int -> [([Int], [Int])]
solve nums maxlen = makePairs (makeSums nums maxlen []) []
    
 
solve' nums maxlen = nub $ concat $ concatMap (mkPair . map snd) $ filter noOne $
                    groupBy ((==) `on` fst) $ sortBy (compare `on` fst) $ 
                    map (\a -> (sum a,a)) $
                    filter ((<=maxlen).length) $ tail $ subsequences nums
    where noOne [x] = False
          noOne _ = True
          mkPair [x,y] = [[(x,y)]]
          mkPair (x:xs) = map ((,)x) xs : mkPair xs
 
solve'' nums maxlen = concat $ concatMap (mkPair . map snd) $ filter noOne $
                    groupBy ((==) `on` fst) $ sortBy (compare `on` fst) $ 
                    map (\a -> (sum a,a)) $
                    filter ((<=maxlen).length) $ tail $ subsequences nums
    where noOne [x] = False
          noOne _ = True
          mkPair [x,y] = [[(x,y)]]
          mkPair (x:xs) = map ((,)x) xs : mkPair xs
 
bench f nums maxlen = do
       begT <- getCurrentTime
       print $ f nums maxlen
       endT <- getCurrentTime
       print $ diffUTCTime endT begT 
       
main:: IO () 
main = do
       bench solve'' [1,2,3,4,5,6] 4
       bench solve' [1,2,3,4,5,6] 4
       bench solve [1,2,3,4,5,6] 4
И, вообще, по одному разу функцию вызывать для сравнения скорости не корректно (тем более мерить отдельной утилитой, т.е. мерить время загрузки программы).
Можно попробовать поставить пакет, типа criterion .
Я, как то ставил, демонстрировал тут его выводы. Но с ним, тоже надо аккуратно, документацию прочитать. А то лень испортит результаты.
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
31.05.2015, 15:55
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Кстати, у Вас совсем не то выдаёт
в смысле?
0
Модератор
 Аватар для Curry
5158 / 3488 / 536
Регистрация: 01.06.2013
Сообщений: 7,568
Записей в блоге: 9
31.05.2015, 16:20
Цитата Сообщение от pycture Посмотреть сообщение
в смысле?
В прямом. Кстати, как на F# запомнить время до и после выполнения ф-ии и вывести разницу во времени в мс?
Что бы напрямую в программе померить.

Добавлено через 15 минут

Не по теме:

Больше месяца назад ставил VS 2013 community (что предложили на сайте, то и ставил), сказали бесплатно. Щас запустил - "триал истёк! Давай свою запись в мелкософт! Теперь, телефон давай!". Уху ... ладно. Уже не надо мне ничего знать про то что как в F# делать.

0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
31.05.2015, 16:36
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
В прямом.
> List.sum [5; 8; 9; 10; 11; 12], List.sum [6; 7; 9; 10; 11; 12];;
val it : int * int = (55, 55)
что не так?
0
31.05.2015, 16:54  [ТС]

Не по теме:

Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Больше месяца назад ставил VS 2013 community (что предложили на сайте, то и ставил), сказали бесплатно. Щас запустил - "триал истёк! Давай свою запись в мелкософт! Теперь, телефон давай!". Уху ... ладно. Уже не надо мне ничего знать про то что как в F# делать.
Рекомендую. https://www.linqpad.net/
Хорошая программа и бесплатная. (Если купить лицензию, то добавится intellisense)

0
31.05.2015, 17:02

Не по теме:

Кликните здесь для просмотра всего текста
Цитата Сообщение от Shamil1 Посмотреть сообщение
Хорошая программа и бесплатная. (Если купить лицензию, то добавится intellisense)
community тоже бесплатен с intellisense и кучей всего. создать учетку при желании не проблема

0
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886
31.05.2015, 22:13  [ТС]
KolodeznyDiver,
У Вас в алгоритме вторая часть имеет сложность https://www.cyberforum.ru/cgi-bin/latex.cgi?O(n log n), а у меня была https://www.cyberforum.ru/cgi-bin/latex.cgi?O(n^2). Я немного изменил код, теперь у меня тоже https://www.cyberforum.ru/cgi-bin/latex.cgi?O(n log n) (где n - количество подпоследовательностей).

з.ы. F# у меня правильный ответ даёт.
0
Модератор
 Аватар для Curry
5158 / 3488 / 536
Регистрация: 01.06.2013
Сообщений: 7,568
Записей в блоге: 9
31.05.2015, 22:40
Цитата Сообщение от Shamil1 Посмотреть сообщение
Я немного изменил код, теперь у меня тоже
Замечательно. А посмотреть этот новый код можно, или он только для посвящённых?
0
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886
01.06.2015, 03:57  [ТС]
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Замечательно. А посмотреть этот новый код можно, или он только для посвящённых?
Так он всё по той же ссылке доступен:
C#
Да там всего две строчки поменялись. Вот как теперь выглядит вторая часть:
C#
1
2
3
4
5
6
7
8
9
    sums.Sort((x,y) => x.Sum.CompareTo(y.Sum));
    var res = new List<Tuple<NodeList,NodeList>>();
    for(int i = 0; i < sums.Count; i++)
        for(int j = i + 1; j < sums.Count; j++)
        {
            if(sums[i].Sum != sums[j].Sum)
                break;
            res.Add(Tuple.Create(sums[i], sums[j]));
        }
Добавлено через 2 минуты
Haskell код я не трогал пока. Я хотел ссылку про GHC прочитать (когда будет время).

Добавлено через 3 часа 29 минут
Статью пока не читал, но функцию подправил:
1. Добавил сортировку, после чего filter заменил на takeWhile
2. Добавил самодельный map, принимающий начальное значение (чтобы не складывать потом последовательности, а добавлять по одному элементу в начало)
(Первое изменение без второго почти не улучшало результат)

Результаты тестов (для "solve [1..14] 7"):
Code
1
2
3
4
[([7,8,10,11,12,13,14],[6,9,10,11,12,13,14])]
"0.562489s  without nub"
[([3],[2,1])]
"0.358085s  with sort takeWhile"
Моя ошибка заключалось в том, что я, накапливая последовательность в аккумуляторе, аккумулятор поставил на первое место в операции ++ (то есть, перебирал весь аккумулятор на каждом шаге). Из-за этого результат C# так сильно отличался от Haskell (сейчас практически одинаковое время).

Добавлено через 3 минуты
Вот так новый код выглядит:
Haskell
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
import Data.Time
import Data.List
import Data.Function
 
data NodeList = NodeList 
    { nlRoot  :: [Int]
    , nlLength :: Int
    , nlSum    :: Int }
    deriving (Show)
 
map1 _ q []    = q
map1 f q (x:xs)  = f x : map1 f q xs
 
makeSums :: [Int] -> Int -> [NodeList] -> [NodeList]
makeSums [] _  acc         = acc    
makeSums (x:xs) maxlen acc = makeSums xs maxlen $ addNodeList $ map1 addNode acc $ filter lessLen acc
    where addNodeList y = (NodeList [x] 1 x) : y
          addNode (NodeList root len sum) = NodeList (x:root) (len+1) (sum+x) 
          lessLen y = nlLength y < maxlen
 
makePairs4 :: [NodeList] -> [([Int], [Int])] -> [([Int], [Int])]
makePairs4 [] acc     = acc
makePairs4 (x:xs) acc = makePairs4 xs $ map1 pairNodes acc $ takeWhile sameSum xs 
    where sameSum y = nlSum x == (nlSum y)
          pairNodes y = (nlRoot x, nlRoot y)
    
solve4 :: [Int] -> Int -> [([Int], [Int])]
solve4 nums maxlen = makePairs4 (sortBy (compare `on` nlSum) (makeSums nums maxlen [])) []
Есть готовый аналог для моей map1?
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
01.06.2015, 08:21
Цитата Сообщение от Shamil1 Посмотреть сообщение
Результаты тестов (для "solve [1..14] 7")
solve [1..16] 8 во времени не укладывается
0
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886
01.06.2015, 08:56  [ТС]
Цитата Сообщение от pycture Посмотреть сообщение
solve [1..16] 8 во времени не укладывается
Логично. У нас было 0.56+0.35 =0.91 для [1..14] 7. Мы увеличили "три раза": 14->15, 15->16, 7->8. Каждое увеличение увеличивает время выполнения примерно в два раза. 0.91*8 = 5.7 > 5
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
01.06.2015, 08:58
Цитата Сообщение от Shamil1 Посмотреть сообщение
Логично.
так и с# неукладывается http://ideone.com/2SYHYv
0
Модератор
Эксперт функциональных языков программирования
3136 / 2283 / 469
Регистрация: 26.03.2015
Сообщений: 8,886
01.06.2015, 09:07  [ТС]
p.s. Кроме того, точность подобных замеров (через текущее время) довольно низкая. Время может отличаться от запуска к запуску.

Добавлено через 8 минут
Вот результаты с моего ноутбука (во второй строке - длина ответа):
Code
1
2
3
4
5
6
7
8
9
10
00.000251 (GCs=  0) 08
622
00.000291 (GCs=  0) 10
7565
00.002655 (GCs=  0) 12
93034
00.121343 (GCs=  4) 14
1174462
02.464010 (GCs= 44) 16
15227432
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
01.06.2015, 09:11
Цитата Сообщение от Shamil1 Посмотреть сообщение
Кроме того, точность подобных замеров (через текущее время) довольно низкая. Время может отличаться от запуска к запуску.
оно не настолько плавает что б погрешности в секунды давать.
http://ideone.com/EdPtIT 7 [1..14] 0.46s
http://ideone.com/A3e5gi 8 [1..16] 3.01s
наверно в haskell'ом и c# варианте есть еще куда стремиться
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.06.2015, 09:11
Помогаю со студенческими работами здесь

Создать и заполнить третий массив, суммами чисел с одинаковыми индексами
Даны два двумерные массивы одинакового размера, заполнение случайными числами. Создать и заполнить третий массив, суммами чисел с...

Подпоследовательности С#
Помогите решить задачу. Дан массив: {xi}, i = 1...n. Найти номера начального и конечного элементов последней подпоследовательности...

Выражение с суммами
Необходимо посчитать выражение с 2-мя суммами a+Ʃ(2*l^3+3*l^2+1) 2+Ʃ(k^2+2) для l от...

Подсчет подпоследовательности
Нужно найти длину самой большой подпоследовательности, состоящей только из цифр. Считается, что последовательность считана вся, если уже...

последовательность и ее подпоследовательности
существует например последовательность xn=\lg x * sin(\pi *x/2) предел ее подпоследовательность x2n=0 - сходящаяся а x2n+1=\propto -...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru