Problem 107

http://projecteuler.net/index.php?section=problems&id=107

どうみても最小木問題です。本当に(ry

というわけで、今回はライブラリを使ってみた。
なんと、最小木を求める関数があるという充実ぶり。

import Data.List
import Data.Array
import Data.Graph.Inductive

mkEdge' xs = map triple.filter((0/=).snd).assocs.listArray ((1,1),(m,n)).concat$xs
    where m = length.head$xs
          n = length xs
          triple (x,y) = (fst x, snd x ,y)

mkNetwork :: [[Int]]->Gr () Int
mkNetwork =mkGraph (zip [1..40] (repeat ())).mkEdge'

getNet :: IO [[Int]]
getNet = do f <- readFile "network.txt"
            return.map (read.("["++).(++"]").map g).lines $ f
    where g x | x == '-' = '0'
              | x /= '-' =  x

getNodes'' (LP xs) = [x|x<-xs]

main = do net <-getNet
          let mst = msTree.mkNetwork$net
              m = sum.map snd.nub.concat.map getNodes''$mst
              n = sum.concat$net
          print $ div n 2 - m

とりあえず、このGraph.Inductiveの使い方を理解するのに時間がかかった。
帰納的にグラフを定義するというのはプログラミングでは新鮮。
関数型言語帰納的定義が多いから、まぁ普通なのか?

getNode''がきにくわないが、よしとしよう。

Problem 104

http://projecteuler.net/index.php?section=problems&id=104

単純な解法

import Data.List
fib = 0:1:zipWith (+) fib (tail fib)
fibMod = map (flip mod (10^9))$0:1:zipWith (+) fibMod (tail fibMod)
main = print.findIndex pandigit.zip fibMod $fib
    where pandigit (x,y) = "123456789"==(sort.show) x 
                           && "123456789"== (sort.take 9.show) y

あまり速くないが、他の方法を思いつかない。

Problem 105

http://projecteuler.net/index.php?section=problems&id=105

ちょっと考えたら、シンプルな解法に気がついた。

import Data.List
monotone xs = all (f.sort$xs) [1..length xs `div` 2]
    where f ys n = (sum.take (n+1)) ys > (sum.take n.reverse) ys

subsetSumNeq xs = all (f xs) [1..length xs `div` 2]
    where f ys n = all (null.tail).group.sort.map sum. comb ys $ n

specialSum xs = monotone xs &&  subsetSumNeq xs

main = do f <- readFile "sets.txt"
          let sets = map (read.("["++).(++"]")).lines $ f
          print.sum.map sum.filter specialSum $ sets

comb _ 0 = [[]]
comb [] _ = []
comb (x:xs) (n+1) = map (x:) (comb xs n) ++ comb xs (n+1)

Problem 106

http://projecteuler.net/index.php?section=problems&id=106

とりあえず問題文を理解するのにすごい時間がかかった。
なんで、n=4で25になるのか分からなかった。
とりあえず原因は
問題文がどこまでリストの要素が昇順である仮定をつかっているのか
明記してなかった点にあると思う。
(と、問題文のせいにしてみる。)

import Data.List

needTest (x,y) = (or $ zipWith (>) x y)&&(or $ zipWith (<) x y)
divid (x:xs) = [(x:ys,xs\\ys)|ys<-comb xs (length xs `div` 2)]

tests m = [filter needTest$divid xs|n<-[4,6..m`div`2*2],xs<-comb [1..m] n]

main = print.sum.map length.tests$12

comb _ 0 = [[]]
comb [] _ = []
comb (x:xs) (n+1) = map (x:) (comb xs n) ++ comb xs (n+1)

考えたアルゴリズム
偶数個の要素をとってくる
二分割をいろいろ考える
testが必要なものだけ取り出す
以上

効率は悪い。しかし、高々12。tractableです。