Link to Snippet

Ninety-Nine F# Problems - Problems 90 - 94 - Miscellaneous problems]

These are F# solutions of Ninety-Nine Haskell Problems which are themselves translations of Ninety-Nine Lisp Problems and Ninety-Nine Prolog Problems. The solutions are hidden so you can try to solve them yourself.

/// Ninety-Nine F# Problems - Problems 90 - 94////// These are F# solutions of Ninety-Nine Haskell Problems /// (http://www.haskell.org/haskellwiki/H-99:_Ninety-Nine_Haskell_Problems), /// which are themselves translations of Ninety-Nine Lisp Problems/// (http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html)/// and Ninety-Nine Prolog Problems/// (https://sites.google.com/site/prologsite/prolog-problems).////// If you would like to contribute a solution or fix any bugs, send /// an email to paks at kitiara dot org with the subject "99 F# problems". /// I'll try to update the problem as soon as possible.////// The problems have different levels of difficulty. Those marked with a single asterisk (*) /// are easy. If you have successfully solved the preceeding problems you should be able to /// solve them within a few (say 15) minutes. Problems marked with two asterisks (**) are of /// intermediate difficulty. If you are a skilled F# programmer it shouldn't take you more than /// 30-90 minutes to solve them. Problems marked with three asterisks (***) are more difficult. /// You may need more time (i.e. a few hours or more) to find a good solution////// Though the problems number from 1 to 99, there are some gaps and some additions marked with /// letters. There are actually only 88 problems.///

/// This is a classical problem in computer science. The objective is to place eight queens on a /// chessboard so that no two queens are attacking each other; i.e., no two queens are in the /// same row, the same column, or on the same diagonal./// /// Hint: Represent the positions of the queens as a list of numbers 1..N. Example: /// [4,2,7,3,6,8,5,1] means that the queen in the first column is in row 4, the queen in the /// second column is in row 2, etc. Use the generate-and-test paradigm./// /// Example in F#: /// /// > queens 8 |> Seq.length;;/// val it : int = 92/// > queens 8 |> Seq.head;;/// val it : int list = [1; 5; 8; 6; 3; 7; 2; 4]/// > queens 20 |> Seq.head;;/// val it : int list =/// [1; 3; 5; 2; 4; 13; 15; 12; 18; 20; 17; 9; 16; 19; 8; 10; 7; 14; 6; 11](Solution)

/// In a K-regular graph all nodes have a degree of K; i.e. the number of edges incident in each /// node is K. How many (non-isomorphic!) 3-regular graphs with 6 nodes are there?(Solution needed)

// instead of solving the problem for 8 queens lets solve if for N queens.// To solve the problem we are going to start with an empty board and then we're going// add queen to it for each row. Elimitating invalid solutions. To do that we need a function// (invalidPosition) that detects if one queen is in conflict with another one. And another // function (validSolution) that would test if the queen that we're adding is not in // conflict with any queen already on the board. // Also, the solution is going to return a a sequence of solutions instead of a list.// That way we can get one solution realy fast if that is only what we care. For example // getting all the solutions for a 20x20 board would take a long time, but finding // the first solution only takes 5 seconds.//

// Wikipedia has a nice article about this problem http://en.wikipedia.org/wiki/Knights_tour//// The way this algorithm works is like this. We create a set (board) with all the positions// in the board that have not being used. Also we have a function (moves) that returns a // list of posible moves from the current position. The variable 'validMoves' is the result of// removing all the positions returned by 'moves' that are not in the set 'board' (positions // that are still available). If validMoves is empty, that means that we can not move // anymore. If at that time the board is empty, we have a solution! Otherwise we remove the // current position from the board add the curent position to the tour and continue to one // of the valid moves.// Now, the trick to make the algorithm converge is to move first to the valid position // that has the less options once we move (Warnsdorff's rule).//

// After some searching on the internet I couldn't find an algorithm for Graceful labeling.// So I decided to go the brute force route. I knew this would work with the first the example// but I wasn't sure if it would work for the second tree (a tree with 14 Nodes means that we have// 14! (87,178,291,200) posible ways to tag the tree).// Luckly, it did!!

// To represent the trees, I decided to use a tuple with a list of nodes and a list of tuples with the edgestype 'a Graph = 'a list * ('a * 'a) list

// Now I knew how to generate permutations in F# from this snippet: http://fssnip.net/48// But the problem was, that implementation was using lists and it would not work to generate the // 87 billion permutations for the 14 node tree. Then I remember the LazyList type in the F#// Power Pack. Now I can generate the permutations in a lazy way and pray that a solution // can be found fast.// Here is the implemetation of using LazyList.

// this is what drives the solution to this problem and // came from the haskell solution.// Here is an example of its use:// > splits [1..4];;// val it : (int list * int list) list =// [([1], [2; 3; 4]); ([1; 2], [3; 4]); ([1; 2; 3], [4])]// As you can see, it returs all the ways we can split a list.let splits xs = List.tail (init (List.zip (inits xs) (tails xs)))

// Now that we're armed with all these functions, we're ready to tackle the real problem.

// The goal of the function expressions is to build all valid expressions and its value given a // list of numbers. First we split the list in all posible ways (1). Then we take// the left side of the split and build all the valid expresions (2). We do the same for the// right side (3). Now we combine the two expresions with all the operators (4). If the operation// is valid, we add it to the list of expressions (5,6).let rec expressions = function | [x] -> [(Val x, x)] | xs -> [ for xsl, xsr in splits xs do (* 1 *) for (expl, vall) in expressions xsl do (* 2 *) for (expr, valr) in expressions xsr do (* 3 *) for op in [Add; Sub; Mult; Div] do (* 4 *) if valid op vall valr then (* 5 *) yield (App (op, expl, expr) ,app op vall valr) (* 6 *)]

// Now that we have a way of generating valid expressions, it's time to// generate the equaions. Again, we split the list of numbers (1). Then we generate the // list of expressions from the left side of the split (2). Same with the right side (3).// If both expressions have the same value, add it to our soutions (4,5).let equations = function | [] -> failwith "error: empty list" | [_] -> failwith "error: singleton list" | xs -> [for xsl, xsr in splits xs do (* 1 *) for el, vl in expressions xsl do (* 2 *) for er, vr in expressions xsr do (* 3 *) if vl = vr then (* 4 *) yield (el, er) (* 5 *)]