兰福德顺序执行哈斯克尔或C [英] Langford sequence implementation Haskell or C

查看:284
本文介绍了兰福德顺序执行哈斯克尔或C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在组合数学中,兰福德配对,也称为兰福德序列,是<$的列的排序C $ C> 2N 号 1,1,2,2,...,N, n,其中两个的是一个单位开中,两个二进制补码是两个单元分开,并且更一般每个号码k的两个副本k个单元间隔。

In combinatorial mathematics, a Langford pairing, also called a Langford sequence, is a permutation of the sequence of 2n numbers 1, 1, 2, 2, ..., n,n in which the two ones are one unit apart, the two twos are two units apart, and more generally the two copies of each number k are k units apart.

例如:

兰福德配对的 N = 3 由序列给出 2,3,1,2,1,3。

Langford pairing for n = 3 is given by the sequence 2,3,1,2,1,3.

  • 什么是解决这个问题的好方法哈斯克尔 C
  • 您可以建议一个算法来解决这个问题(不要想用蛮力)?

--------------------------编辑----------------- -----
我们如何定义的数学规则,把@雷夫的code在Haskell

--------------------------EDIT----------------------
How could we define the mathematical rules to put @Rafe's code in haskell

推荐答案

您想找到一个赋值给变量{P1,P2,...,PN}(其中PI是第一次出现的位置i )与控股为每个PI以下限制:

You want to find an assignment to the variables {p1, p2, ..., pn} (where pi is the position of the first occurrence of 'i') with the following constraints holding for each pi:

  • PI在1 ..(1 + N-1)
  • 如果PI = K然后FORALL PJ其中j!=我
  • PJ!= K
  • PJ!= K + I
  • PJ = K - !Ĵ
  • PJ = K + I - J

您在这里需要一个合理的搜索策略。一个好的选择是在每个选择点选择的可能值的最小剩余设置PI。

You need a sensible search strategy here. A good choice is to at each choice point choose the pi with the smallest remaining set of possible values.

干杯!

这是一个主要功能版本的当务之急版本我第一次写(见下面第一个附录)。这主要是功能性的,即在搜索树的每个顶点相关联的状态是独立于其他国家,因此没有必要对那种线索或机器。不过,我已经使用势在必行code实现每个新域从父域集的副本集的构建。

This is a "mostly functional" version of the imperative version I first wrote (see first addendum below). It's mostly functional in the sense that the state associated with each vertex in the search tree is independent of all other state, hence there's no need for a trail or machinery of that kind. However, I have used imperative code to implement the construction of each new domain set from a copy of the parent domain set.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MostlyFunctionalLangford
{
    class Program
    {
        // An (effectively functional) program to compute Langford sequences.
        static void Main(string[] args)
        {
            var n = 7;
            var DInit = InitLangford(n);
            var DSoln = Search(DInit);
            if (DSoln != null)
            {
                Console.WriteLine();
                Console.WriteLine("Solution for n = {0}:", n);
                WriteSolution(DSoln);
            }
            else
            {
                Console.WriteLine();
                Console.WriteLine("No solution for n = {0}.", n);
            }
            Console.Read();
        }

        // The largest integer in the Langford sequence we are looking for.
        // [I could infer N from the size of the domain array, but this is neater.]
        static int N;

        // ---- Integer domain manipulation. ----

        // Find the least bit in a domain; return 0 if the domain is empty.
        private static long LeastBitInDomain(long d)
        {
            return d & ~(d - 1);
        }

        // Remove a bit from a domain.
        private static long RemoveBitFromDomain(long d, long b)
        {
            return d & ~b;
        }

        private static bool DomainIsEmpty(long d)
        {
            return d == 0;
        }

        private static bool DomainIsSingleton(long d)
        {
            return (d == LeastBitInDomain(d));
        }

        // Return the size of a domain.
        private static int DomainSize(long d)
        {
            var size = 0;
            while (!DomainIsEmpty(d))
            {
                d = RemoveBitFromDomain(d, LeastBitInDomain(d));
                size++;
            }
            return size;
        }

        // Find the k with the smallest non-singleton domain D[k].
        // Returns zero if none exists.
        private static int SmallestUndecidedDomainIndex(long[] D)
        {
            var bestK = 0;
            var bestKSize = int.MaxValue;
            for (var k = 1; k <= N && 2 < bestKSize; k++)
            {
                var kSize = DomainSize(D[k]);
                if (2 <= kSize && kSize < bestKSize)
                {
                    bestK = k;
                    bestKSize = kSize;
                }
            }
            return bestK;
        }

        // Obtain a copy of a domain.
        private static long[] CopyOfDomain(long[] D)
        {
            var DCopy = new long[N + 1];
            for (var i = 1; i <= N; i++) DCopy[i] = D[i];
            return DCopy;
        }

        // Destructively prune a domain by setting D[k] = {b}.
        // Returns false iff this exhausts some domain.
        private static bool Prune(long[] D, int k, long b)
        {
            for (var j = 1; j <= N; j++)
            {
                if (j == k)
                {
                    D[j] = b;
                }
                else
                {
                    var dj = D[j];
                    dj = RemoveBitFromDomain(dj, b);
                    dj = RemoveBitFromDomain(dj, b << (k + 1));
                    dj = RemoveBitFromDomain(dj, b >> (j + 1));
                    dj = RemoveBitFromDomain(dj, (b << (k + 1)) >> (j + 1));
                    if (DomainIsEmpty(dj)) return false;
                    if (dj != D[j] && DomainIsSingleton(dj) && !Prune(D, j, dj)) return false;
                }
            }
            return true;
        }

        // Search for a solution from a given set of domains.
        // Returns the solution domain on success.
        // Returns null on failure.
        private static long[] Search(long[] D)
        {
            var k = SmallestUndecidedDomainIndex(D);
            if (k == 0) return D;

            // Branch on k, trying each possible assignment.
            var dk = D[k];
            while (!DomainIsEmpty(dk))
            {
                var b = LeastBitInDomain(dk);
                dk = RemoveBitFromDomain(dk, b);
                var DKeqB = CopyOfDomain(D);
                if (Prune(DKeqB, k, b))
                {
                    var DSoln = Search(DKeqB);
                    if (DSoln != null) return DSoln;
                }
            }

            // Search failed.
            return null;
        }

        // Set up the problem.
        private static long[] InitLangford(int n)
        {
            N = n;
            var D = new long[N + 1];
            var bs = (1L << (N + N - 1)) - 1;
            for (var k = 1; k <= N; k++)
            {
                D[k] = bs & ~1;
                bs >>= 1;
            }
            return D;
        }

        // Print out a solution.
        private static void WriteSolution(long[] D)
        {
            var l = new int[N + N + 1];
            for (var k = 1; k <= N; k++)
            {
                for (var i = 1; i <= N + N; i++)
                {
                    if (D[k] == 1L << i)
                    {
                        l[i] = k;
                        l[i + k + 1] = k;
                    }
                }
            }
            for (var i = 1; i < l.Length; i++)
            {
                Console.Write("{0} ", l[i]);
            }
            Console.WriteLine();
        }
    }
}

我决定写一个C#程序来解决兰福德问题。它的运行速度很快达到N = 16,但此后则需要更改为使用,因为它重新presents领域的位模式多头。

I decided to write a C# program to solve Langford problems. It runs very quickly up to n = 16, but thereafter you need to change it to use longs since it represents domains as bit patterns.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Langford
{
    // Compute Langford sequences.  A Langford sequence L(n) is a permutation of [1, 1, 2, 2, ..., n, n] such
    // that the pair of 1s is separated by 1 place, the pair of 2s is separated by 2 places, and so forth.
    //
    class Program
    {
        static void Main(string[] args)
        {
            var n = 16;
            InitLangford(n);
            WriteDomains();
            if (FindSolution())
            {
                Console.WriteLine();
                Console.WriteLine("Solution for n = {0}:", n);
                WriteDomains();
            }
            else
            {
                Console.WriteLine();
                Console.WriteLine("No solution for n = {0}.", n);
            }
            Console.Read();
        }

        // The n in L(n).
        private static int N;

        // D[k] is the set of unexcluded possible positions in the solution of the first k for each pair of ks.
        // Each domain is represented as a bit pattern, where bit i is set iff i is in D[k].
        private static int[] D;

        // The trail records domain changes to undo on backtracking.  T[2k] gives the element in D to undo;
        // T[2k+1] gives the value to which it must be restored.
        private static List<int> T = new List<int> { };

        // This is the index of the next unused entry in the trail.
        private static int TTop;

        // Extend the trail to restore D[k] on backtracking.
        private static void TrailDomainValue(int k)
        {
            if (TTop == T.Count)
            {
                T.Add(0);
                T.Add(0);
            }
            T[TTop++] = k;
            T[TTop++] = D[k];
        }

        // Undo the trail to some earlier point.
        private static void UntrailTo(int checkPoint)
        {
            //Console.WriteLine("Backtracking...");

            while (TTop != checkPoint)
            {
                var d = T[--TTop];
                var k = T[--TTop];
                D[k] = d;
            }
        }

        // Find the least bit in a domain; return 0 if the domain is empty.
        private static int LeastBitInDomain(int d)
        {
            return d & ~(d - 1);
        }

        // Remove a bit from a domain.
        private static int RemoveBitFromDomain(int d, int b)
        {
            return d & ~b;
        }

        private static bool DomainIsEmpty(int d)
        {
            return d == 0;
        }

        private static bool DomainIsSingleton(int d)
        {
            return (d == LeastBitInDomain(d));
        }

        // Return the size of a domain.
        private static int DomainSize(int d)
        {
            var size = 0;
            while (!DomainIsEmpty(d))
            {
                d = RemoveBitFromDomain(d, LeastBitInDomain(d));
                size++;
            }
            return size;
        }

        // Find the k with the smallest non-singleton domain D[k].
        // Returns zero if none exists.
        private static int SmallestUndecidedDomainIndex()
        {
            var bestK = 0;
            var bestKSize = int.MaxValue;
            for (var k = 1; k <= N && 2 < bestKSize; k++)
            {
                var kSize = DomainSize(D[k]);
                if (2 <= kSize && kSize < bestKSize)
                {
                    bestK = k;
                    bestKSize = kSize;
                }
            }
            return bestK;
        }

        // Prune the other domains when domain k is reduced to a singleton.
        // Return false iff this exhausts some domain.
        private static bool Prune(int k)
        {
            var newSingletons = new Queue<int>();
            newSingletons.Enqueue(k);

            while (newSingletons.Count != 0)
            {
                k = newSingletons.Dequeue();

                //Console.WriteLine("Pruning from domain {0}.", k);

                var b = D[k];
                for (var j = 1; j <= N; j++)
                {
                    if (j == k) continue;
                    var dOrig = D[j];
                    var d = dOrig;
                    d = RemoveBitFromDomain(d, b);
                    d = RemoveBitFromDomain(d, b << (k + 1));
                    d = RemoveBitFromDomain(d, b >> (j + 1));
                    d = RemoveBitFromDomain(d, (b << (k + 1)) >> (j + 1));
                    if (DomainIsEmpty(d)) return false;
                    if (d != dOrig)
                    {
                        TrailDomainValue(j);
                        D[j] = d;
                        if (DomainIsSingleton(d)) newSingletons.Enqueue(j);
                    }
                }

                //WriteDomains();
            }
            return true;
        }

        // Search for a solution.  Return false iff one is not found.
        private static bool FindSolution() {
            var k = SmallestUndecidedDomainIndex();
            if (k == 0) return true;

            // Branch on k, trying each possible assignment.
            var dOrig = D[k];
            var d = dOrig;
            var checkPoint = TTop;
            while (!DomainIsEmpty(d))
            {
                var b = LeastBitInDomain(d);
                d = RemoveBitFromDomain(d, b);
                D[k] = b;

                //Console.WriteLine();
                //Console.WriteLine("Branching on domain {0}.", k);

                if (Prune(k) && FindSolution()) return true;
                UntrailTo(checkPoint);
            }
            D[k] = dOrig;
            return false;
        }

        // Print out a representation of the domains.
        private static void WriteDomains()
        {
            for (var k = 1; k <= N; k++)
            {
                Console.Write("D[{0,3}] = {{", k);
                for (var i = 1; i <= N + N; i++)
                {
                    Console.Write("{0, 3}", ( (1 << i) & D[k]) != 0 ? i.ToString() 
                                            : DomainIsSingleton(D[k]) && (1 << i) == (D[k] << (k + 1)) ? "x"
                                            : "");
                }
                Console.WriteLine(" }");
            }
        }

        // Set up the problem.
        private static void InitLangford(int n)
        {
            N = n;
            D = new int[N + 1];
            var bs = (1 << (N + N - 1)) - 1;
            for (var k = 1; k <= N; k++)
            {
                D[k] = bs & ~1;
                bs >>= 1;
            }
        }
    }
}

这篇关于兰福德顺序执行哈斯克尔或C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆