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 দিয়ে স্থানীয়ভাবে পরীক্ষিত (যেমন সতর্কতাটি প্রিন্ট করা হয়নি - টিআইও ডিবাগ ট্যাব দেখুন)
- না। কখনো। ব্যবহার করুন। জাভা। 1. এটি সাধারণভাবে জাভার চেয়ে বেশি ভার্বোজ।
এটি চেইনটি ভেঙে দিতে পারে।
- ফাঁকটি (7 দিন এবং 48 মিনিট) এই উত্তরের তৈরি ফাঁকটির চেয়ে বেশি নয় যা পূর্ববর্তীটির চেয়ে 7 দিন এবং 1 ঘন্টা 25 মিনিট পরে ।
বড় বাইকাউন্টে নতুন রেকর্ড! যেহেতু আমি (ভুল করে?) ট্যাবগুলির পরিবর্তে ফাঁকা স্থান ব্যবহার করি, তাই বাইকাউন্টগুলি প্রয়োজনের চেয়ে বড়। আমার মেশিনে এটি 9550 বাইট। (এই সংশোধনটি লেখার সময়)
- পরবর্তী ক্রম ।
- কোডটি, তার বর্তমান আকারে, কেবল ক্রমের প্রথম 20 টি পদ মুদ্রণ করে। তবে এটি যাতে পরিবর্তন করতে এটি প্রথম 1000 আইটেম ছাপে হবে সহজ (পরিবর্তনের ফলে
20
এ for (int i = 0; i < 20; ++i)
থেকে 1000
)
হ্যাঁ! এটি OEIS পৃষ্ঠায় তালিকাবদ্ধের চেয়ে আরও শর্তগুলি গণনা করতে পারে! (প্রথমবারের জন্য, চ্যালেঞ্জের জন্য আমার জাভা ব্যবহার করা দরকার) যদি না ওইআইএসের আরও কোথাও শর্ত না থাকে ...
দ্রুত ব্যাখ্যা
ক্রম বর্ণনার ব্যাখ্যা।
অনুক্রমটি প্রতিসম গ্রুপ সি 2 ভি সহ বিনামূল্যে ননপ্লানার পলিনয়েডের সংখ্যার জন্য জিজ্ঞাসা করে , যেখানে:
- পলিনয়েড: (পলিন হাইড্রোকার্বনের গাণিতিক মডেল) গাছগুলি (বা অবনতিজনিত ক্ষেত্রে, একক প্রান্তে) সহ ষড়ভুজীয় জালায় এমবেড করা যেতে পারে।
উদাহরণস্বরূপ, গাছগুলি বিবেচনা করুন
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)
মঞ্জুর জন্য সূত্রটি (ওইআইএস পৃষ্ঠায় তালিকাভুক্ত) নিই । আমি কাগজে ব্যাখ্যাটি পড়িনি।
[এই অংশটি ঠিক করুন]
অবশ্যই, পরিকল্পনাকারী গণনা ননপ্ল্যানার গণনা করার চেয়ে সহজ। কাগজও তাই করে।
জ্যামিতিকভাবে প্ল্যানার পলিনয়েডস (ওভারল্যাপিং শীর্ষগুলি ছাড়াই) কম্পিউটার প্রোগ্রামিং দ্বারা অঙ্কিত হয়। এইভাবে জ্যামিতিকভাবে নন-প্ল্যানার পলিনয়েডগুলির সংখ্যা অ্যাক্সেসযোগ্য হয়ে ওঠে।
সুতরাং ... প্রোগ্রামটি প্ল্যানার পলিনয়েডের সংখ্যা গণনা করে এবং এটি মোট থেকে বিয়োগ করে।
গাছটি যাইহোক প্ল্যানার হওয়ার কারণে এটির ■
প্রতিফলনের সমতল রয়েছে। সুতরাং শর্তটি "2D উপস্থাপনে প্রতিচ্ছবিটির অক্ষ সহ গাছের সংখ্যা গণনা করতে" নামিয়ে আনে।
নিষ্পাপ উপায়টি হ'ল 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 দ্বারা ভাগ করার কথাও মনে রাখবেন।