281. जावा 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);
}
}
इसे ऑनलाइन आज़माएं!
पक्षीय लेख:
- जावा 5 के साथ स्थानीय रूप से परीक्षण किया गया (जैसे कि चेतावनी मुद्रित नहीं है - TIO डिबग टैब देखें)
- मत करो। कभी। उपयोग। जावा। 1. यह सामान्य रूप से जावा से अधिक क्रिया है।
इससे चेन टूट सकती है।
- अंतराल (7 दिन और 48 मिनट) इस उत्तर द्वारा बनाई गई खाई से अधिक नहीं है , जो पिछले एक की तुलना में 7 दिन और 1 घंटे 25 मिनट बाद है ।
बड़े bytecount पर नया रिकॉर्ड! क्योंकि मैं (गलती से?) टैब के बजाय रिक्त स्थान का उपयोग करता हूं, बाईटेकाउंट आवश्यकता से अधिक बड़ा है। मेरी मशीन पर यह 9550 बाइट्स है। (इस संशोधन को लिखते समय)
- अगला अनुक्रम ।
- कोड, अपने वर्तमान रूप में, केवल अनुक्रम के पहले 20 शब्दों को प्रिंट करता है। हालांकि यह इतना बदलने के लिए है कि यह पहली 1000 मदों प्रिंट होगा आसान है (परिवर्तन से
20
में for (int i = 0; i < 20; ++i)
करने के लिए 1000
)
वाह! यह OEIS पृष्ठ पर सूचीबद्ध से अधिक शब्दों की गणना कर सकता है! (पहली बार, एक चुनौती के लिए मुझे जावा का उपयोग करने की आवश्यकता है) जब तक कि OEIS के पास कहीं और शर्तें न हों ...
त्वरित स्पष्टीकरण
अनुक्रम वर्णन की व्याख्या।
अनुक्रम सममिति समूह C 2v के साथ मुक्त नॉनप्लेनर पॉलीनेयॉइड की संख्या के लिए पूछता है , जहां:
- पॉलेनॉइड: (पॉलीन हाइड्रोकार्बन के गणितीय मॉडल) पेड़ों (या पतित मामले में, एकल शीर्ष) के साथ हेक्सागोनल जाली में एम्बेड किया जा सकता है।
उदाहरण के लिए, पेड़ों पर विचार करें
O O O O (3)
| \ / \
| \ / \
O --- O --- O O --- O O --- O
| \
| (2) \
(1) O O
पहले वाले को हेक्सागोनल जाली में एम्बेड नहीं किया जा सकता है, जबकि दूसरा एक कर सकता है। उस विशेष एम्बेडिंग को तीसरे पेड़ से अलग माना जाता है।
- नॉनप्लेनर पॉलेनॉइड: पेड़ों की एम्बेडिंग जैसे कि दो अतिव्यापी वर्धमान होते हैं।
(2)
और (3)
ऊपर पेड़ हैं। यह एक, हालांकि, नॉनप्लेनर है:
O---O O
/ \
/ \
O O
\ /
\ /
O --- O
(7 कोने और 6 किनारे हैं)
- मुक्त पॉलीएनोइड: एक पॉलीएनॉइड के वेरिएंट, जो रोटेशन और प्रतिबिंब द्वारा प्राप्त किया जा सकता है, को एक के रूप में गिना जाता है।
- सी 2 वी समूह: पॉलेनॉइड को केवल तब गिना जाता है जब उनके पास प्रतिबिंब के 2 लंबवत विमान होते हैं, और नहीं।
उदाहरण के लिए, 2 कोने के साथ एकमात्र पॉलेनॉइड
O --- O
प्रतिबिंब के 3 विमान हैं: क्षैतिज एक -
, ऊर्ध्वाधर एक |
और कंप्यूटर स्क्रीन के समानांतर एक ■
। वह बहुत ज्यादा है।
दूसरी ओर, यह एक
O --- O
\
\
O
प्रतिबिंब के 2 विमान हैं: /
और ■
।
विधि की व्याख्या
और अब, वास्तव में संख्या की गणना करने के तरीके पर दृष्टिकोण।
सबसे पहले, मैं सूत्र a(n) = A000063(n + 2) - A000936(n)
(OEIS पृष्ठ पर सूचीबद्ध) को प्रदान करता हूं । मैंने पेपर में स्पष्टीकरण नहीं पढ़ा।
[TODO इस हिस्से को ठीक करें]
बेशक, नॉनप्लेनर की गिनती की तुलना में प्लानर की गिनती करना आसान है। यही कागज भी करता है।
कंप्यूटर प्रोग्रामिंग द्वारा ज्यामितीय प्लेनर पॉलीनोइड्स (अतिव्यापी वर्टिकल के बिना) गणना की जाती हैं। इस प्रकार जियोमेट्रिकली नॉनप्लेनर पॉलीनोइड्स की संख्या सुलभ हो जाती है।
इसलिए ... कार्यक्रम में प्लानर पॉलेनॉइड की संख्या गिना जाता है, और इसे कुल से घटाता है।
क्योंकि पेड़ वैसे भी प्लेनर होता है, लेकिन जाहिर तौर पर इसमें ■
प्रतिबिंब का तल होता है। तो हालत "2 डी प्रतिनिधित्व में प्रतिबिंब की धुरी के साथ पेड़ की संख्या की गिनती" तक उबलती है।
भोली तरह n
नोड्स के साथ सभी पेड़ों को उत्पन्न करेगा , और सही समरूपता के लिए जांच करेगा। हालाँकि, क्योंकि हम केवल परावर्तन की धुरी के साथ पेड़ों की संख्या का पता लगाना चाहते हैं, हम केवल एक आधे पर सभी संभव आधा पेड़ उत्पन्न कर सकते हैं, उन्हें अक्ष के माध्यम से दर्पण कर सकते हैं, और फिर सही समरूपता के लिए जांच कर सकते हैं। इसके अलावा, क्योंकि पॉलीनोइड्स उत्पन्न होते हैं (प्लेनर) पेड़, यह बिल्कुल एक बार प्रतिबिंब की धुरी को छूना चाहिए।
फ़ंक्शन public static Graph[] expand(Graph[] graphs, Point.Predicate fn)
ग्राफ़ की एक सरणी लेता है, प्रत्येक में n
नोड्स होते हैं, और ग्राफ़ की एक सरणी आउटपुट करते हैं, प्रत्येक में n+1
नोड्स होते हैं, एक दूसरे के बराबर नहीं (अनुवाद के तहत) - जैसे कि जोड़ा नोड को विधेय को संतुष्ट करना होगा fn
।
प्रतिबिंब के 2 संभावित अक्षों पर विचार करें: एक जो एक शीर्ष के माध्यम से जाता है और किनारों ( x = 0
) के साथ मेल खाता है , और एक जो एक किनारे के लंबवत द्विभाजक है ( 2x = y
)। हम उनमें से केवल एक ही ले सकते हैं क्योंकि उत्पन्न रेखांकन आइसोमॉर्फिक हैं, वैसे भी।
तो, पहली धुरी के लिए x = 0
, हम आधार ग्राफ से शुरू करते हैं जिसमें एक एकल नोड होता है (1, 0)
(मामले n
में विषम है) या बीच के किनारे के साथ दो नोड्स (1, 0) - (2, 0)
(यदि मामला समान n
है), और फिर नोड्स का विस्तार करें y > 0
। यह कार्यक्रम के "परावर्तन प्रकार 1" अनुभाग द्वारा किया जाता है, और फिर प्रत्येक उत्पन्न ग्राफ के लिए, एक्स अक्ष x = 0
( g.reflectSelfX()
) के माध्यम से स्वयं को प्रतिबिंबित (दर्पण ), और फिर जांचें कि क्या यह सही समरूपता है।
हालांकि, ध्यान दें कि यदि n
2 से विभाज्य है, तो इस तरह से हमने प्रत्येक ग्राफ को दो बार गिना है, क्योंकि हम अक्ष द्वारा इसकी दर्पण छवि भी बनाते हैं 2x = y + 3
।
(2 नारंगी वाले नोट करें)
अक्ष के समान 2x = y
, यदि (और केवल अगर) n
भी है, तो हम बिंदु से शुरू (1, 1)
करते हैं, ऐसे ग्राफ़ बनाते हैं 2*x > y
, और उनमें से प्रत्येक को 2x = y
अक्ष पर प्रतिबिंबित करते हैं ( g.reflectSelfType2()
), से कनेक्ट (1, 0)
करें (1, 1)
, और जांचें कि क्या उनके पास सही समरूपता है। 2 से भाग करना भी याद रखें।