首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扩展OEIS:计算钻石斜率

扩展OEIS:计算钻石斜率
EN

Code Golf用户
提问于 2015-06-04 12:22:11
回答 1查看 2K关注 0票数 51

我保证,这将是我最后一次挑战迪阿美的倾斜(至少在一段时间内)。好的一面是,这个挑战与ASCII艺术没有任何关系,也不是一个代码高尔夫,所以这实际上是完全不同的。

因此,作为提醒,每个六边形都可以用三颗不同的钻石命名:

一个有趣的问题是,对于给定的六边形大小,这些倾斜物中有多少存在。这些数字似乎已经相当深入地研究过,可以在OEIS A008793中找到。

然而,如果我们问到旋转和反射有多少个倾斜点,问题就会变得更加棘手。例如,对于边长N= 2,存在以下20个加法:

代码语言:javascript
复制
   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /\_\_\   /\_\_\   /\_\_\   /\_\_\   /_/\_\   /_/\_\   /\_\_\   /_/\_\   /_/\_\   /_/\_\ 
 /\/\_\_\ /\/_/\_\ /\/_/_/\ /\/_/\_\ /\_\/\_\ /\_\/_/\ /\/_/_/\ /\_\/\_\ /\_\/_/\ /_/\/\_\
 \/\/_/_/ \/\_\/_/ \/\_\_\/ \/_/\/_/ \/\_\/_/ \/\_\_\/ \/_/\_\/ \/_/\/_/ \/_/\_\/ \_\/\/_/
  \/_/_/   \/_/_/   \/_/_/   \_\/_/   \/_/_/   \/_/_/   \_\/_/   \_\/_/   \_\/_/   \_\/_/ 
   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /_/_/\   /\_\_\   /_/\_\   /_/_/\   /_/\_\   /_/\_\   /_/_/\   /_/_/\   /_/_/\   /_/_/\ 
 /\_\_\/\ /\/_/_/\ /_/\/_/\ /\_\_\/\ /\_\/_/\ /_/\/_/\ /_/\_\/\ /\_\_\/\ /_/\_\/\ /_/_/\/\
 \/\_\_\/ \/_/_/\/ \_\/\_\/ \/_/\_\/ \/_/_/\/ \_\/_/\/ \_\/\_\/ \/_/_/\/ \_\/_/\/ \_\_\/\/
  \/_/_/   \_\_\/   \_\/_/   \_\/_/   \_\_\/   \_\_\/   \_\/_/   \_\_\/   \_\_\/   \_\_\/ 

但其中许多在旋转和反射下是相同的。如果考虑到这些对称性,只剩下6种不同的倾斜现象:

代码语言:javascript
复制
   ____     ____     ____     ____     ____     ____  
  /\_\_\   /\_\_\   /\_\_\   /_/\_\   /_/\_\   /_/\_\ 
 /\/\_\_\ /\/_/\_\ /\/_/_/\ /\_\/_/\ /\_\/_/\ /_/\/\_\
 \/\/_/_/ \/\_\/_/ \/\_\_\/ \/\_\_\/ \/_/\_\/ \_\/\/_/
  \/_/_/   \/_/_/   \/_/_/   \/_/_/   \_\/_/   \_\/_/ 

   2        2        6        6        1        3

其中数字表示每个瓷砖的多重性。请注意,对于较大的六边形,也有多重数为4和12的倾斜。

看来,向对称方向倾斜的次数没有得到充分的研究。OEIS条目A066931只列出以下五个术语:

代码语言:javascript
复制
1, 1, 6, 113, 20174

其中第一个项表示边长N = 0,最后一个项表示边长N = 4

我相信我们还能做得更好!

您的任务是计算给定边长的倾斜数。

我是最快代码。您的分数将是最高边长的N,您的代码将在30分钟内在我的机器上产生正确的结果。在领带的情况下,我将接受提交的结果,为该N最快。

像往常一样,你不能硬编码结果,你已经知道,以赢得平局.求解N = 3的算法应与求解N = 5的算法相同。

您提交的内存不得超过4GB。如果你的操作接近这个极限,我会给你一些回旋余地,但是如果你一直高于这个限制,或者如果你明显地超过了这个极限,我不会把你提交的N计算在内。

我将测试所有的提交在我的Windows 8机器,所以确保您的语言选择是免费提供在Windows上。唯一的例外是Mathematica (因为我碰巧有它的许可证)。请包括有关如何编译/运行代码的说明。

当然,你可以在你自己的时间内计算更多的术语(对于科学,以及其他人对照他们的数字),但是你的答案的分数将在30分钟内决定。

EN

回答 1

Code Golf用户

回答已采纳

发布于 2015-06-12 22:44:47

代数,图论,M bius反演,研究和Java

六边形的对称群是12阶的二面体群,它是由60度旋转和一个镜面翻转在直径之间产生的。它有16个子群,但其中一些子群是非平凡共轭群(只有反射的子群有3个轴的选择),因此,六边形的平铺可以有10个根本不同的对称:

三角格的一个子集的金刚石倾斜数可以是作为行列式计算,所以我最初的方法是为六边形的每个对称建立一个行列式,计算出至少有这些对称的倾斜数;然后在其偏序集的关联代数中使用M bius反演(基本上是包含排除原理的推广),计算出对称群恰好是这10个情形中每一个的倾斜数。然而,有些对称有着令人讨厌的边缘条件,所以我不得不对许多决定因素进行指数相加。幸运的是,为n < 10获得的值为我提供了足够的数据,能够识别出OEIS中的相关序列,并将一个封闭形式(对于允许有限乘积的“封闭”值)拼凑在一起。在正式写作中有一些关于序列的讨论,以及对证明的引用,这是我准备用来证明OEIS序列更新的理由。

一旦处理了重复计算,结果是十个值中有四个完全抵消了,所以我们只需要计算剩下的六个,然后做加权和。

在我的机器上,这段代码用于N=1000所需的时间不到30秒。

代码语言:javascript
复制
import java.math.BigInteger;

public class OptimisedCounter {
    private static int[] minp = new int[2];

    public static void main(String[] args) {
        if (args.length > 0) {
            for (String arg : args) System.out.println(count(Integer.parseInt(arg)));
        }
        else {
            for (int n = 0; n < 16; n++) {
                System.out.format("%d\t%s\n", n, count(n));
            }
        }
    }

    private static BigInteger count(int n) {
        if (n == 0) return BigInteger.ONE;

        if (minp.length < 3*n) {
            int[] wider = new int[3*n];
            System.arraycopy(minp, 0, wider, 0, minp.length);
            for (int x = minp.length; x < wider.length; x++) {
                // Find the smallest prime which divides x
                for (wider[x] = 2; x % wider[x] != 0; wider[x]++) { /* Do nothing */ }
            }
            minp = wider;
        }

        BigInteger E = countE(n), R2 = countR2(n), F = countF(n), R3 = countR3(n), R = countR(n), FR = countFR(n);
        BigInteger sum = E.add(R3);
        sum = sum.add(R2.add(R).multiply(BigInteger.valueOf(2)));
        sum = sum.add(F.add(FR).multiply(BigInteger.valueOf(3)));
        return sum.divide(BigInteger.valueOf(12));
    }

    private static BigInteger countE(int n) {
        int[] w = new int[3*n];
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= i + n; j++) w[j]--;
            for (int j = i + n + 1; j <= i + 2*n; j++) w[j]++;
        }
        return powerProd(w);
    }

    private static BigInteger countR2(int n) {
        int[] w = new int[3*n];
        for (int i = 0; i < n; i++) {
            w[3*i+2]++;
            for (int j = 3*i + 1; j <= 2*i + n + 1; j++) w[j]--;
            for (int j = 2*i + n + 1; j <= i + n + n; j++) w[j]++;
        }
        return powerProd(w);
    }

    private static BigInteger countF(int n) {
        int[] w = new int[3*n];
        for (int i = 0; i < n; i++) {
            for (int j = 2*i + 1; j <= 2*i + n; j++) w[j]--;
            for (int j = i + n + 1; j <= i + 2*n; j++) w[j]++;
        }
        return powerProd(w);
    }

    private static BigInteger countR3(int n) {
        if ((n & 1) == 1) return BigInteger.ZERO;
        return countE(n / 2).pow(2);
    }

    private static BigInteger countR(int n) {
        if ((n & 1) == 1) return BigInteger.ZERO;
        int m = n / 2;
        int[] w = new int[3*m-1];
        for (int i = 0; i < m; i++) {
            for (int j = 1; j <= 3*i+1; j++) w[j] += 2;
            for (int j = 1; j <= i + m; j++) w[j] -= 2;
        }
        return powerProd(w);
    }

    private static BigInteger countFR(int n) {
        if ((n & 1) == 1) return BigInteger.ZERO;
        int m = n / 2;
        int[] w = new int[3*n-2];
        for (int j = 1; j <= m; j++) w[j]--;
        for (int j = 2*m; j <= 3*m-1; j++) w[j]++;
        for (int i = 0; i <= 2*m-3; i++) {
            for (int j = i + 2*m + 1; j <= i + 4*m; j++) w[j]++;
            for (int j = 2*i + 3; j <= 2*i + 2*m + 2; j++) w[j]--;
        }
        return powerProd(w);
    }

    private static BigInteger powerProd(int[] w) {
        BigInteger result = BigInteger.ONE;
        for (int x = w.length - 1; x > 1; x--) {
            if (w[x] == 0) continue;

            int p = minp[x];
            if (p == x) result = result.multiply(BigInteger.valueOf(p).pow(w[p]));
            else {
                // Redistribute it. This should ensure we avoid negatives.
                w[p] += w[x];
                w[x / p] += w[x];
            }
        }

        return result;
    }
}
票数 85
EN
页面原文内容由Code Golf提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codegolf.stackexchange.com/questions/51266

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档