281. Java 5, 11628 바이트, A000947
// package oeis_challenge;
import java.util.*;
import java.lang.*;
class Main {
// static void assert(boolean cond) {
// if (!cond)
// throw new Error("Assertion failed!");
// }
/* Use the formula a(n) = A000063(n + 2) - A000936(n).
It's unfair that I use the formula of "number of free polyenoid with n
nodes and symmetry point group C_{2v}" (formula listed in A000063)
without understanding why it's true...
*/
static int catalan(int x) {
int ans = 1;
for (int i = 1; i <= x; ++i)
ans = ans * (2*x+1-i) / i;
return ans / -~x;
}
static int A63(int n) {
int ans = catalan(n/2 - 1);
if (n%4 == 0) ans -= catalan(n/4 - 1);
if (n%6 == 0) ans -= catalan(n/6 - 1);
return ans;
}
static class Point implements Comparable<Point> {
final int x, y;
Point(int _x, int _y) {
x = _x; y = _y;
}
/// @return true if this is a point, false otherwise (this is a vector)
public boolean isPoint() {
return (x + y) % 3 != 0;
}
/// Translate this point by a vector.
public Point add(Point p) {
assert(this.isPoint() && ! p.isPoint());
return new Point(x + p.x, y + p.y);
}
/// Reflect this point along x-axis.
public Point reflectX() {
return new Point(x - y, -y);
}
/// Rotate this point 60 degrees counter-clockwise.
public Point rot60() {
return new Point(x - y, x);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point p = (Point) o;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return 21521 * (3491 + x) + y;
}
public String toString() {
// return String.format("(%d, %d)", x, y);
return String.format("setxy %d %d", x * 50 - y * 25, y * 40);
}
public int compareTo(Point p) {
int a = Integer.valueOf(x).compareTo(p.x);
if (a != 0) return a;
return Integer.valueOf(y).compareTo(p.y);
}
/// Helper class.
static interface Predicate {
abstract boolean test(Point p);
}
static abstract class UnaryFunction {
abstract Point apply(Point p);
}
}
static class Edge implements Comparable<Edge> {
final Point a, b; // guarantee a < b
Edge(Point x, Point y) {
assert x != y;
if (x.compareTo(y) > 0) { // y < x
a = y; b = x;
} else {
a = x; b = y;
}
}
public int compareTo(Edge e) {
int x = a.compareTo(e.a);
if (x != 0) return x;
return b.compareTo(e.b);
}
}
/// A graph consists of multiple {@code Point}s.
static class Graph {
private HashMap<Point, Point> points;
public Graph() {
points = new HashMap<Point, Point>();
}
public Graph(Graph g) {
points = new HashMap<Point, Point>(g.points);
}
public void add(Point p, Point root) {
assert(p.isPoint());
assert(root.isPoint());
assert(p == root || points.containsKey(root));
points.put(p, root);
}
public Graph map(Point.UnaryFunction fn) {
Graph result = new Graph();
for (Map.Entry<Point, Point> pq : points.entrySet()) {
Point p = pq.getKey(), q = pq.getValue();
assert(p.isPoint()) : p;
assert(q.isPoint()) : q;
p = fn.apply(p); assert(p.isPoint()) : p;
q = fn.apply(q); assert(q.isPoint()) : q;
result.points.put(p, q);
}
return result;
}
public Graph reflectX() {
return this.map(new Point.UnaryFunction() {
public Point apply(Point p) {
return p.reflectX();
}
});
}
public Graph rot60() {
return this.map(new Point.UnaryFunction() {
public Point apply(Point p) {
return p.rot60();
}
});
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o.getClass() != getClass()) return false;
Graph g = (Graph) o;
return points.equals(g.points);
}
@Override
public int hashCode() {
return points.hashCode();
}
Graph[] expand(Point.Predicate fn) {
List<Graph> result = new ArrayList<Graph>();
for (Point p : points.keySet()) {
int[] deltaX = new int[] { -1, 0, 1, 1, 0, -1};
int[] deltaY = new int[] { 0, 1, 1, 0, -1, -1};
for (int i = 6; i --> 0;) {
Point p1 = new Point(p.x + deltaX[i], p.y + deltaY[i]);
if (points.containsKey(p1) || !fn.test(p1)
|| !p1.isPoint()) continue;
Graph g = new Graph(this);
g.add(p1, p);
result.add(g);
}
}
return result.toArray(new Graph[0]);
}
public static Graph[] expand(Graph[] graphs, Point.Predicate fn) {
Set<Graph> result = new HashSet<Graph>();
for (Graph g0 : graphs) {
Graph[] g = g0.expand(fn);
for (Graph g1 : g) {
if (result.contains(g1)) continue;
result.add(g1);
}
}
return result.toArray(new Graph[0]);
}
private Edge[] edges() {
List<Edge> result = new ArrayList<Edge>();
for (Map.Entry<Point, Point> pq : points.entrySet()) {
Point p = pq.getKey(), q = pq.getValue();
if (p.equals(q)) continue;
result.add(new Edge(p, q));
}
return result.toArray(new Edge[0]);
}
/**
* Check if two graphs are isomorphic... under translation.
* @return {@code true} if {@code this} is isomorphic
* under translation, {@code false} otherwise.
*/
public boolean isomorphic(Graph g) {
if (points.size() != g.points.size()) return false;
Edge[] a = this.edges();
Edge[] b = g.edges();
Arrays.sort(a);
Arrays.sort(b);
// for (Edge e : b)
// System.err.println(e.a + " - " + e.b);
// System.err.println("------- >><< ");
assert (a.length > 0);
assert (a.length == b.length);
int a_bx = a[0].a.x - b[0].a.x, a_by = a[0].a.y - b[0].a.y;
for (int i = 0; i < a.length; ++i) {
if (a_bx != a[i].a.x - b[i].a.x ||
a_by != a[i].a.y - b[i].a.y) return false;
if (a_bx != a[i].b.x - b[i].b.x ||
a_by != a[i].b.y - b[i].b.y) return false;
}
return true;
}
// C_{2v}.
public boolean correctSymmetry() {
Graph[] graphs = new Graph[6];
graphs[0] = this.reflectX();
for (int i = 1; i < 6; ++i) graphs[i] = graphs[i-1].rot60();
assert(graphs[5].rot60().isomorphic(graphs[0]));
int count = 0;
for (Graph g : graphs) {
if (this.isomorphic(g)) ++count;
// if (count >= 2) {
// return false;
// }
}
// if (count > 1) System.err.format("too much: %d%n", count);
assert(count > 0);
return count == 1; // which is, basically, true
}
public void reflectSelfType2() {
Graph g = this.map(new Point.UnaryFunction() {
public Point apply(Point p) {
return new Point(p.y - p.x, p.y);
}
});
Point p = new Point(1, 1);
assert (p.equals(points.get(p)));
points.putAll(g.points);
assert (p.equals(points.get(p)));
Point q = new Point(0, 1);
assert (q.equals(points.get(q)));
points.put(p, q);
}
public void reflectSelfX() {
Graph g = this.reflectX();
points.putAll(g.points); // duplicates doesn't matter
}
}
static int A936(int n) {
// if (true) return (new int[]{0, 0, 0, 1, 1, 2, 4, 4, 12, 10, 29, 27, 88, 76, 247, 217, 722, 638, 2134, 1901, 6413})[n];
// some unreachable codes here for testing.
int ans = 0;
if (n % 2 == 0) { // reflection type 2. (through line 2x == y)
Graph[] graphs = new Graph[1];
graphs[0] = new Graph();
Point p = new Point(1, 1);
graphs[0].add(p, p);
for (int i = n / 2 - 1; i --> 0;)
graphs = Graph.expand(graphs, new Point.Predicate() {
public boolean test(Point p) {
return 2*p.x > p.y;
}
});
int count = 0;
for (Graph g : graphs) {
g.reflectSelfType2();
if (g.correctSymmetry()) {
++count;
// for (Edge e : g.edges())
// System.err.println(e.a + " - " + e.b);
// System.err.println("------*");
}
// else System.err.println("Failed");
}
assert (count%2 == 0);
// System.err.println("A936(" + n + ") count = " + count + " -> " + (count/2));
ans += count / 2;
}
// Reflection type 1. (reflectX)
Graph[] graphs = new Graph[1];
graphs[0] = new Graph();
Point p = new Point(1, 0);
graphs[0].add(p, p);
if (n % 2 == 0) graphs[0].add(new Point(2, 0), p);
for (int i = (n-1) / 2; i --> 0;)
graphs = Graph.expand(graphs, new Point.Predicate() {
public boolean test(Point p) {
return p.y > 0;
}
});
int count = 0;
for (Graph g : graphs) {
g.reflectSelfX();
if (g.correctSymmetry()) {
++count;
// for (Edge e : g.edges())
// System.err.printf(
// "pu %s pd %s\n"
// // "%s - %s%n"
// , e.a, e.b);
// System.err.println("-------/");
}
// else System.err.println("Failed");
}
if(n % 2 == 0) {
assert(count % 2 == 0);
count /= 2;
}
ans += count;
// System.err.println("A936(" + n + ") = " + ans);
return ans;
}
public static void main(String[] args) {
// Probably
if (! "1.5.0_22".equals(System.getProperty("java.version"))) {
System.err.println("Warning: Java version is not 1.5.0_22");
}
// A936(6);
for (int i = 0; i < 20; ++i)
System.out.println(i + " | " + (A63(i+9) - A936(i+7)));
//A936(i+2);
}
}
온라인으로 사용해보십시오!
사이드 노트 :
- Java 5를 사용하여 로컬에서 테스트했습니다 (경고가 인쇄되지 않도록-TIO 디버그 탭 참조)
- 하지마 이제까지. 사용하다. 자바. 1. 일반적으로 Java보다 더 장황합니다.
체인이 파손될 수 있습니다.
- 간격 (7 일 및 48 분) 은이 답변에 의해 생성 된 간격 ( 이전의 것보다 7 일 1 시간 25 분 늦음)을 넘지 않습니다.
큰 바이트 수에 대한 새로운 기록! 내가 (실수로?) 탭 대신 공백을 사용하기 때문에 바이트 수가 필요한 것보다 큽니다. 내 컴퓨터에서는 9550 바이트입니다. (본 개정 시점)
- 다음 순서 .
- 현재 형식의 코드는 시퀀스의 처음 20 개 항만 인쇄합니다. 그러나 그것이 처음 1000 개 항목을 인쇄 할 정도로 쉽게 변경할 수 있습니다 (변경하여
20의를 for (int i = 0; i < 20; ++i)로 1000)
예이! OEIS 페이지에 나열된 것보다 더 많은 용어를 계산할 수 있습니다! OEIS에 어딘가에 더 많은 용어가 없다면 (처음으로 Java를 사용해야합니다 .)
빠른 설명
시퀀스 설명에 대한 설명
이 시퀀스는 대칭 그룹 C 2v 를 갖는 자유 비평면 폴리에 노이드의 수를 요청합니다 .
- 폴리에 노이드 (polyenoid) : (폴리 엔 탄화수소의 수학적 모델) 트리 (또는 축퇴 된 경우 단일 버텍스)는 육각형 격자에 포함될 수 있습니다.
예를 들어, 나무를 고려하십시오
O O O O (3)
| \ / \
| \ / \
O --- O --- O O --- O O --- O
| \
| (2) \
(1) O O
첫 번째는 6 각형 격자에 포함될 수 없지만 두 번째는 6 각형 격자에 포함될 수 없습니다. 이 특정 임베딩은 세 번째 트리와 다른 것으로 간주됩니다.
- 비평면 폴리에 노이드 : 두 개의 겹치는 정점이 존재하도록 나무를 포함시킵니다.
(2)그리고 (3)나무 위의 평면이다. 그러나 이것은 비평면입니다.
O---O O
/ \
/ \
O O
\ /
\ /
O --- O
(정점 7 개와 모서리 6 개가 있습니다)
- 유리 폴리에 노이드 : 회전 및 반사에 의해 얻을 수있는 하나의 폴리에 노이드 변형이 하나로 계산됩니다.

- C 2v 그룹 : 폴리에 노이드는 두 개의 수직 반사 평면을 갖고 더 이상없는 경우에만 계산됩니다.
예를 들어 정점이 2 개인 유일한 폴리에 노이드
O --- O
수평면 -, 수직면 |, 컴퓨터 화면과 평행 한 3 개의 반 사면이 있습니다 ■. 너무 많아
반면에,이 하나
O --- O
\
\
O
반사의 2 개면을 가지고 /와 ■.
방법 설명
그리고 지금, 실제로 숫자를 세는 방법에 대한 접근법.
먼저, 나는 공식을 a(n) = A000063(n + 2) - A000936(n) (OEIS 페이지에 등재)을 당연한 것으로 생각합니다. 나는 논문의 설명을 읽지 않았다.
[TODO이 부분 수정]
물론, 평면을 계산하는 것은 비평면을 계산하는 것보다 쉽습니다. 그것이 종이의 기능이기도합니다.
기하학적 평면 폴리에 노이드 (겹치는 정점이없는)는 컴퓨터 프로그래밍으로 열거됩니다. 따라서 기하학적 비평면 폴리에 노이드의 수에 접근 할 수있게됩니다.
그래서 ... 프로그램은 평면 폴리에 노이드의 수를 세어 총계에서 뺍니다.
어쨌든 나무는 평면이기 때문에 분명히 ■반 사면이 있습니다. 따라서 조건은 "2D 표현에서 리플렉션 축이있는 트리 수"로 줄어 듭니다.
순진한 방법은 n노드 가있는 모든 트리를 생성하고 올바른 대칭을 확인하는 것입니다. 그러나 리플렉션 축이있는 트리 수만 찾으려고하기 때문에 가능한 모든 반 트리를 반으로 생성하고이를 축을 통해 미러링 한 다음 올바른 대칭을 확인할 수 있습니다. 또한, 생성 된 폴리에 노이드는 (평면) 나무이기 때문에 반사 축을 정확히 한 번만 터치해야합니다.
이 함수 public static Graph[] expand(Graph[] graphs, Point.Predicate fn)는 그래프의 배열을 가져옵니다. 각 n노드 에는 노드가 있고 그래프 배열을 출력합니다. 각 n+1노드에는 서로 같지 않은 노드 가 있습니다 (번역 중). 추가 된 노드가 조건자를 만족해야합니다 fn.
가능한 두 개의 반사 축을 고려하십시오. 하나는 꼭지점을 통과하고 모서리 ( x = 0) 와 일치 하고 다른 하나는 모서리 ( )의 수직 이등분선입니다 2x = y. 어쨌든 생성 된 그래프는 동형이기 때문에 그중 하나만 취할 수 있습니다.

따라서 첫 번째 축의 x = 0경우 기본 그래프에서 시작하여 단일 노드 (1, 0)( n홀수 인 경우 ) 또는 가장자리가있는 (1, 0) - (2, 0)( 두 경우 인 경우 ) 두 노드로 구성된 n다음 노드를 확장합니다 y > 0. 프로그램의 "반사 유형 1"섹션에서 수행 한 다음 생성 된 각 그래프에 대해 X 축 x = 0( g.reflectSelfX())을 통해 자신을 반사 (거울) 한 다음 올바른 대칭이 있는지 확인하십시오.
그러나 n2로 나눌 수 있으면 축으로 미러 이미지를 생성하기 때문에 각 그래프를 두 번 계산합니다 2x = y + 3.

(오렌지 2 개 참고)
axis 2x = y와 비슷하지만 (그리고 if 만) n짝수이면 점에서 시작 (1, 1)하여 그래프와 같은 2*x > y각 그래프를 생성 하고 2x = y축 ( g.reflectSelfType2())에 각각 반영 하고 연결 (1, 0)하고 (1, 1)대칭이 올바른지 확인합니다. 2로 나누는 것도 잊지 마십시오.