بوت لتتريس والرسوم المتحركة الهندسة العكسية. تحليل المسار المحمول من بطولة البرمجة الثانية


الفائزين المسار المحمول

في العام الماضي ، عقدت ياندكس بطولتين للبرمجة عبر الإنترنت. نستمر في نشر تحليلات مهام البطولة الثانية. نذكرك أنه تم تقديم أربعة مسارات للمشاركين: التعلم الآلي ، الواجهة الأمامية ، تطوير الأجهزة المحمولة ، الخلفية. إليك مناقشة لجولة التأهيل لمطوري الأجهزة المحمولة - 121 ممن اجتازوا المؤهلات ثم شاركوا في النهائي. تم اختراع المهام بواسطة متخصصين من Yandex.Browser وفرق أخرى من بوابة البحث. في هذا المحور ، سوف نتطرق إلى موضوع الخوارزميات الجينية ، ونكتب روبوتًا لـ Tetris ونخوض البحث بطرق مختلفة لنظامي Android و iOS.

الكابلات

بواسطة: سيرجي Myasnikov
كل اللغاتPython 3.7.3 و Python 2.7
المهلة4 ق20 ثانية
حد الذاكرة256 ميغابايت
دخولالمدخلات القياسية أو المدخلات
استنتاجالإخراج القياسي أو الإخراج
تم جلب أجهزة الكمبيوتر N إلى المكتب الجديد. لا يسمح التلسكوب الراديوي القريب باستخدام Wi-Fi للاتصال ، وسيتعين على مكتب المساعدة تنظيم شبكة باستخدام كبلات LAN. بعد تجميع كل الكابلات الموجودة في الزوايا ، تمكن المسؤولون من توصيل أزواج K من أجهزة الكمبيوتر. بعد تعب يوم عمل طويل ، لجأ طاقم مكتب المساعدة إليك للحصول على المساعدة - لحساب الميزانية اللازمة لإكمال المهمة. لذلك لديك قائمة بأزواج M من أجهزة الكمبيوتر التي يمكنها توصيل المسؤولين ، وتكلفة كل كبل. عند بدء العمل ، عثرت على خطأ في نظام حساب التكلفة - بدلاً من زيادة التكاليف ، فإنها تتضاعف - لذا فإن الكبل ذي القيمة 4 والكبل بقيمة 3 معًا ليس 7 ، كما يشير المنطق ، ولكن 12.

لإكمال المهمة ، تحتاج إلى حساب تكلفة الكبلات الكافية لتنظيم شبكة متصلة - بحيث يتم توصيل كل كمبيوتر بكل منهما بشكل مباشر أو غير مباشر.

I / O التنسيقات والأمثلة والملاحظات

تنسيق الإدخال


يحتوي السطر الأول على الأرقام 0 <N <10 6 ، 0 ≤ K <10 6 ، 0 ≤ M <10 6 .

تحتوي أسطر K التالية على أزواج من الأرقام 0 <u، v ≤ N - أرقام أجهزة الكمبيوتر المتصلة بالفعل بواسطة مكتب المساعدة.

تحتوي الأسطر M التالية على ثلاثة أضعاف من الأرقام 0 <u و v ≤ N و 0 <p ≤ 10 9 - عدد أجهزة الكمبيوتر التي يمكن للمسؤولين الاتصال بها باستخدام تكلفة الكبل p.

تنسيق الإخراج


قم بطباعة أقل تكلفة ممكنة من الكابلات لإنشاء شبكة متصلة ، أو -1 إذا كان من المستحيل إنشاء شبكة كاملة.

يمكن أن تكون الإجابة كبيرة جدًا ، لذلك تحتاج إلى إخراجها modulo 2 31 - 1.

مثال 1

دخولاستنتاج
2 0 1
2 1 9
9

مثال 2

دخولاستنتاج
5 0 6
1 3 1
2 4 8
1 4 1
1 2 10
4 1 10
5 3 4
32

مثال 3

دخولاستنتاج
6 0 3
4 3 2
2 6 9
1 4 8
–1

الملاحظات


يمكن أن تصل كمية البيانات المدخلة إلى 30 ميجابايت - انتبه لقراءة السرعة.

قرار


الشبكة الكاملة التي يجب بناؤها لحل المشكلة ليست أكثر من مجرد شجرة تمتد على الحد الأدنى. (نظرًا لأن حواف K قد تمت إضافتها بالفعل في بداية الإنشاء ، فإن الرسم البياني الناتج ليس بالضرورة شجرة ، ولكنه مضمون لاحتواءها.)

في الإعداد الكلاسيكي ، تتضمن مشكلة العثور على الحد الأدنى لشجرة الامتداد تقليل مجموع الحواف ، ولكن من الضروري هنا تقليل المنتج إلى الحد الأدنى. لحسن الحظ ، هذه الشجرتين تتزامن. من السهل إثبات ذلك باستبدال أوزان الحواف باللوغاريتمات الخاصة بها.

الخوارزميات الأكثر شهرة لبناء شجرة تمتد الحد الأدنى هي خوارزميات بريما وكراسكال.

في حالة الرسوم البيانية الكثيفة ، تحتوي خوارزمية Prym على المقاربات O (N 2 ) ، والتي ، نظرًا للتقييد N <10 6 ، لا تسمح باستخدامها لحل كامل للمشكلة. (لكن لاحظ أنه تم تجميع بيانات الاختبار بحيث سجل الحل مع المقاربون المشار إليهم نصف النقطة بالضبط)

تطبيق ساذج لخوارزمية Kruskal الذي يستخدم صفيفًا للحفاظ على معلومات حول التكوين الحالي للمكونات المتصلة بالرسم البياني له مقاربات O (M log M + N 2 ). هنا هو ما يعادل O (N 2 ). للحصول على حل كامل ، تحتاج إلى استخدام بنية بيانات تُعرف باسم نظام اتحاد فك الارتباط (DSU).

تتيح لك DSU إجراء عمليتين: find (x) أوجد "زعيم" المجموعة التي ينتمي إليها x (يتم ترجمة الزعيم عن طريق الحقن إلى رقم المجموعة) ؛ اتحاد (x، y) يجمع بين المجموعات التي ينتمي إليها x و y.

استدلال ضغط المسار ورتبة الجمع بين الاستدلال ، وعادة ما تستخدم في تنفيذ هيكل ، والسماح للمرء لتحقيق سلوك مقارب ، في الحالات العملية يعادل O (1).

افترض أننا استخدمنا DSU للحفاظ على معلومات حول مكونات اتصال الرسم البياني أثناء تنفيذ خوارزمية Kraskal. بعد ذلك سيكون السلوك المقارب للخوارزمية هو O (M log M + N) = O (M log M).

رمز القرار
 public class CablesSolution { private static final long MODULLO = 2147483647L; public static void main(String[] args) { InputReader in = new InputReader(System.in); PrintWriter pw = new PrintWriter(System.out); int n = in.readInt(); int k = in.readInt(); int m = in.readInt(); DisjointUnionSets dsu = new DisjointUnionSets(n + 1); for (int i = 0; i < k; i++) { int u = in.readInt(); int v = in.readInt(); dsu.union(u, v); } Edge[] edges = new Edge[m]; // (4 + 4 + 8) * 2M = 32M for (int i = 0; i < m; i++) { int u = in.readInt(); int v = in.readInt(); long p = in.readLong(); edges[i] = new Edge(u, v, p); } Arrays.sort(edges); long res = 1; boolean addedEdge = false; for (Edge edge : edges) { if (!dsu.check(edge.getU(), edge.getV())) { dsu.union(edge.getU(), edge.getV()); res = (res * edge.getP()) % MODULLO; addedEdge = true; } } if (!dsu.isJoint()) { res = -1; } else if (!addedEdge) { res = 0; } pw.println(res); pw.flush(); pw.close(); } public static class DisjointUnionSets { private int[] rank; // 4M private int[] parent; // 4M DisjointUnionSets(int size) { rank = new int[size]; parent = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; } } int find(int target) { if (parent[target] != target) { parent[target] = find(parent[target]); } return parent[target]; } boolean check(int x, int y) { return find(x) == find(y); } void union(int x, int y) { int xRoot = find(x); int yRoot = find(y); if (xRoot == yRoot) { return; } if (rank[xRoot] < rank[yRoot]) { parent[xRoot] = yRoot; } else if (rank[yRoot] < rank[xRoot]) { parent[yRoot] = xRoot; } else { parent[yRoot] = xRoot; rank[xRoot] = rank[xRoot] + 1; } } boolean isJoint() { int parent = -1; for (int i = 1; i < rank.length; i++) { if (parent == -1) { parent = find(i); } else { if (parent != find(i)) { return false; } } } return true; } } private static class Edge implements Comparable<Edge> { private int u; private int v; private long p; Edge(int u, int v, long p) { this.u = u; this.v = v; this.p = p; } int getU() { return u; } int getV() { return v; } long getP() { return p; } @Override public int compareTo(Edge edge) { return Long.compare(p, edge.p); } } } 

جمل فقدت

بواسطة: ديمتري فيسكو

بالنظر إلى مقاييس التطبيق ، افترض المدير فاسيلي أن الواجهة تفتقر إلى بعض الحماسة التي من شأنها أن تعيق المستخدمين. لذلك ، طلب فاسيلي لتنويع واجهة التطبيق لمصمم ماريا. بعد بضعة مخططات ، بزغت ماريا! الفكرة من البداية تكمن على السطح - اتضح فيما بعد ، تحتاج إلى إضافة رسوم متحركة للنص. اخترنا العديد من النصوص وصنعنا رسومًا متحركة. لسوء الحظ ، بعد الانتهاء من العمل ، تم خلط الرسوم المتحركة ، وفقد النص المصدر لكل منها. ساعد الفريق على فهم النص المتحرك في كل حالة.

تنسيقات I / O ، مثال ، وملاحظات

تنسيق الإدخال


لديك العديد من الملفات النصية مع الرسوم المتحركة المحددة ، لكل منها تحتاج إلى تحديد النص المناسب.

رابط إلى الأرشيف مع ملفات الرسوم المتحركة .

يتم تعريف كل الرسوم المتحركة بواسطة المعلمات:
- canvasWidth canvasHeight - يتم تحديد عرض وارتفاع الحاوية للرسوم المتحركة ، في السطر الأول من الإدخال ،
- numbersCount - يتم تعيين عدد الأرقام المراد تحريكها في السطر الثاني من الإدخال ،
- المستطيل centerX centerY لون زاوية ارتفاع العرض - إعلان المستطيل المتمركز عند نقطة (centerX ، centerY) ، العرض × الارتفاع ، درجة زاوية زاوية الدوران واللون المحدد ،
- دائرة centerX centerY لون نصف القطر - إعلان دائرة مع المركز في النقطة (centerX ، centerY) ، دائرة نصف قطرها دائرة نصف قطرها واللون المحدد.

يمكن أن تحتوي معلمة اللون على القيم {الأسود والأحمر والأبيض والأصفر}. تأخذ المعلمة الزاوية القيم في النطاق (-359 درجة ، 359 درجة).

لكل رقم ، يمكن تحديد عدة أنواع من الرسوم المتحركة في وقت واحد ، والتي يتم تطبيقها بالتوازي. بالإضافة إلى ذلك ، لا يمكن تطبيق كل نوع من الرسوم المتحركة أكثر من مرة على الشكل. يتم تعيين عدد الرسوم المتحركة المطبقة على الشكل بالرقم 0 ⩽ figureAnimationsCount ⩽ بعد إعلان الشكل مباشرةً.

أنواع الرسوم المتحركة:
- تحريك زمن destX desty [دورة] - نقل رقم إلى نقطة (destX ، destY) في المللي ثانية من الوقت.
- تدوير زاوية الوقت [دورة] - دوران الشكل بدرجات زاوية في مللي ثانية.
- مقياس وقت مقياس الدرجات [دورة] - قم بزيادة الرقم بمقدار مقياس الدمل بالميلي ثانية.

إذا تم تحديد المعلمة دورة ، ثم في نهاية الرسوم المتحركة ، تستمر حركتها في الاتجاه المعاكس.

تنسيق الإخراج


النص المعروض عند تشغيل الرسوم المتحركة. لكل ملف رسوم متحركة ، يجب الإشارة إلى الإجابة في سطر جديد. حالة الأحرف في الاستجابة يمكن أن تكون تعسفية. يتم تقييم كل نص موجود في الرسوم المتحركة بـ 10 نقاط.

مثال

دخولاستنتاج
400 400
10
rectangle 69.000 280.000 24.000 24.000 0.000 black
1
move 251.000 72.000 10000 cycle
rectangle 256.000 188.000 24.000 48.000 0.000 black
0
rectangle 232.000 152.000 72.000 24.000 0.000 black
0
rectangle 35.000 400.000 24.000 24.000 0.000 black
1
move 285.000 -96.000 10000 cycle
rectangle 244.000 248.000 48.000 24.000 0.000 black
0
rectangle 300.000 117.000 24.000 48.000 0.000 black
1
move 112.000 164.000 5000
rectangle 136.000 200.000 72.000 24.000 0.000 black
0
rectangle 160.000 236.000 24.000 48.000 0.000 black
0
rectangle 208.000 224.000 24.000 72.000 44.797 black
1
rotate -44.797 5000
rectangle 232.000 200.000 24.000 24.000 0.000 black
0
42

الملاحظات


تصور للرسوم المتحركة من المثال:


قرار


كانت المهمة لتنفيذ الرسوم المتحركة. إذا تم تنفيذ الرسوم المتحركة بشكل صحيح ، فعند التشغيل ، تتم إضافة العديد من العناصر الأولية إلى نص قابل للقراءة. يمكن القيام بالرسوم المتحركة باستخدام أي وسيلة - مدمجة في المنصات المحمولة أو الحلول ذات المستوى الأدنى.

مثال للرسوم المتحركة ( رابط إلى ملف .mov ):



تطبيق مثال باستخدام مكتبة Tkinter من بيثون
 import copy import math import time import tkinter from enum import Enum FRAMES_PER_SECOND = 60 TIME_BETWEEN_FRAMES = int(1000 / FRAMES_PER_SECOND) class Rectangle(object): def __init__(self, left_x, left_y, width, height, color, angle=0.0): self.center_x = left_x + width / 2 self.center_y = left_y + height / 2 self.width = width self.height = height self.color = color self.angle = angle def get_left_x(self): return self.center_x - self.width / 2 def set_left_x(self, left_x): self.center_x = left_x + self.width / 2 def get_left_y(self): return self.center_y - self.height / 2 def set_left_y(self, left_y): self.center_y = left_y + self.height / 2 left_x = property(get_left_x, set_left_x) left_y = property(get_left_y, set_left_y) class Circle(object): def __init__(self, left_x, left_y, radius, color): self.center_x = left_x + radius self.center_y = left_y + radius self.radius = radius self.color = color self.angle = 0 def get_left_x(self): return self.center_x - self.radius def set_left_x(self, left_x): self.center_x = left_x + self.radius def get_left_y(self): return self.center_y - self.radius def set_left_y(self, left_y): self.center_y = left_y + self.radius left_x = property(get_left_x, set_left_x) left_y = property(get_left_y, set_left_y) class AnimationType(Enum): MOVE = 1 ROTATE = 2 SCALE = 3 class Animation(object): def __init__(self, time, cycle): self.time = time self.cycle = cycle def scale(self, time_spent): return 1 def move(self, time_spent): return 0, 0 def angle(self, time_spent): return 0 def _cycle_progress(self, time_spent): if self.cycle: cycle_time = time_spent % (self.time * 2) if cycle_time > self.time: return 1 - (cycle_time - self.time) / self.time else: return cycle_time / self.time else: if time_spent < self.time: cycle_time = time_spent % self.time return cycle_time / self.time else: return 1 class MoveAnimation(Animation): def __init__(self, figure, to_x, to_y, time, cycle): super().__init__(time, cycle) self.from_x = figure.center_x self.from_y = figure.center_y self.to_x = to_x self.to_y = to_y def move(self, time_spent): cycle_progress = super()._cycle_progress(time_spent) diff_x = self.to_x - self.from_x diff_y = self.to_y - self.from_y return diff_x * cycle_progress, diff_y * cycle_progress class ScaleAnimation(Animation): def __init__(self, destination_scale, time, cycle): super().__init__(time, cycle) self.destination_scale = destination_scale def scale(self, time_spent): cycle_progress = super()._cycle_progress(time_spent) return 1 + (self.destination_scale - 1) * cycle_progress class RotateAnimation(Animation): def __init__(self, rotate_angle, time, cycle): super().__init__(time, cycle) self.rotate_angle = rotate_angle def angle(self, time_spent): cycle_progress = super()._cycle_progress(time_spent) return self.rotate_angle * cycle_progress class Transformer(object): def scale(self, scale): pass def move(self, diff_x, diff_y): pass def rotate(self, angle): pass class RectangleTransformer(Transformer): def __init__(self, rectangle): self.rectangle = rectangle def scale(self, scale): self.rectangle.width = self.rectangle.width * scale self.rectangle.height = self.rectangle.height * scale def move(self, diff_x, diff_y): self.rectangle.center_x = self.rectangle.center_x + diff_x self.rectangle.center_y = self.rectangle.center_y + diff_y def rotate(self, angle): self.rectangle.angle = (self.rectangle.angle + angle) % 360 class CircleTransformer(Transformer): def __init__(self, circle): self.circle = circle def scale(self, scale): self.circle.radius = self.circle.radius * scale def move(self, diff_x, diff_y): self.circle.center_x = self.circle.center_x + diff_x self.circle.center_y = self.circle.center_y + diff_y def rotate(self, angle): pass class Drawer(object): def draw(self, canvas, spent_time): pass class AnimationApplier(object): @staticmethod def apply_animations(spent_time, transformer, animations): for animation in animations: transformer.scale(animation.scale(spent_time)) diff_x, diff_y = animation.move(spent_time) transformer.move(diff_x, diff_y) transformer.rotate(animation.angle(spent_time)) class RectangleDrawer(Drawer): def __init__(self, rectangle, animations): self.rectangle = rectangle self.animations = animations def draw(self, canvas, spent_time): rect = self._transform_rect_with_animations(spent_time) rect_points = self._get_rectangle_points(rect) rotated_points = self._rotate(rect_points, rect.angle, [rect.center_x, rect.center_y]) canvas.create_polygon(rotated_points, fill=rect.color) def _transform_rect_with_animations(self, spent_time): rect = copy.copy(self.rectangle) transformer = RectangleTransformer(rect) AnimationApplier.apply_animations(spent_time, transformer, self.animations) return transformer.rectangle @staticmethod def _get_rectangle_points(rect): half_width = rect.width / 2 half_height = rect.height / 2 return [ [rect.center_x - half_width, rect.center_y - half_height], [rect.center_x - half_width, rect.center_y + half_height], [rect.center_x + half_width, rect.center_y + half_height], [rect.center_x + half_width, rect.center_y - half_height] ] @staticmethod def _rotate(points, angle, center): angle = math.radians(angle) cos_val = math.cos(angle) sin_val = math.sin(angle) cx, cy = center new_points = [] for x_old, y_old in points: x_old -= cx y_old -= cy x_new = x_old * cos_val - y_old * sin_val y_new = x_old * sin_val + y_old * cos_val new_points.append([x_new + cx, y_new + cy]) return new_points class CircleDrawer(Drawer): def __init__(self, circle, animations): self.circle = circle self.animations = animations def draw(self, canvas, spent_time): circle = self._transform_rect_with_animations(spent_time) size = circle.radius * 2 canvas.create_oval(circle.left_x, circle.left_y, circle.left_x + size, circle.left_y + size, fill=circle.color) def _transform_rect_with_animations(self, spent_time): circle = copy.copy(self.circle) transformer = CircleTransformer(circle) AnimationApplier.apply_animations(spent_time, transformer, self.animations) return transformer.circle class Scene(object): def __init__(self, canvas, animated_symbols): self.canvas = canvas self.drawers = self._get_generated_drawers(animated_symbols) @staticmethod def _get_generated_drawers(animated_symbols): drawers = [] for animated_symbol in animated_symbols: figure = animated_symbol.figure animations = animated_symbol.animations if isinstance(figure, Rectangle): drawer = RectangleDrawer(figure, animations) elif isinstance(figure, Circle): drawer = CircleDrawer(figure, animations) else: raise Exception() drawers.append(drawer) return drawers def draw(self, time_spent): self.canvas.delete("all") for drawer in self.drawers: drawer.draw(self.canvas, time_spent) self.canvas.pack() class Timer(object): def __init__(self): self.started_time = None def start(self): self.started_time = self._current_time() def time_spent(self): current_time = self._current_time() return current_time - self.started_time @staticmethod def _current_time(): return int(round(time.time() * 1000)) def scene_loop(window, scene, timer): time_spent = timer.time_spent() scene.draw(time_spent) window.after(TIME_BETWEEN_FRAMES, scene_loop, window, scene, timer) def configure_window_location(window, canvas_width, canvas_height): screen_width = window.winfo_screenwidth() screen_height = window.winfo_screenheight() x = (screen_width / 2) - (canvas_width / 2) y = (screen_height / 2) - (canvas_height / 2) window.geometry('%dx%d+%d+%d' % (canvas_width, canvas_height, x, y)) class AnimatedSymbol(object): def __init__(self, figure, animations): self.figure = figure self.animations = animations class AnimationsParser(object): def parse_animated_symbols(self, file_path): with open(file_path) as f: lines = f.readlines() canvas_width, canvas_height = self._parse_size(lines[0]) symbols_count = int(lines[1]) animated_symbols = [] current = 2 for i in range(symbols_count): figure = self._parse_figure(lines[current]) current += 1 symbol_animations = self._parse_animations(figure, current, lines) current += 1 + len(symbol_animations) animated_symbol = AnimatedSymbol(figure, symbol_animations) animated_symbols.append(animated_symbol) return canvas_width, canvas_height, animated_symbols def _parse_size(self, line): parts = line.split(" ") return int(parts[0]), int(parts[1]) def _parse_animations(self, figure, current, lines): animations = [] animations_count = int(lines[current]) for i in range(animations_count): parts = lines[current + i + 1].split(" ") animation = self._parse_animation(figure, parts) animations.append(animation) return animations def _parse_figure(self, line): parts = line.split(" ") if parts[0] == 'rectangle': center_x = float(parts[1]) center_y = float(parts[2]) width = float(parts[3]) height = float(parts[4]) angle = float(parts[5]) color = parts[6].replace('\n', '') figure = Rectangle(center_x - width / 2, center_y - height / 2, width, height, color, angle) elif parts[0] == 'circle': center_x = float(parts[1]) center_y = float(parts[2]) radius = float(parts[3]) color = parts[4].replace('\n', '') figure = Circle(center_x - radius, center_y - radius, radius, color) else: raise Exception() return figure def _parse_animation(self, figure, parts): if parts[0] == "move": animation = self._parse_move_animation(figure, parts) elif parts[0] == "scale": animation = self._parse_scale_animation(parts) elif parts[0] == "rotate": animation = self._parse_rotate_animation(parts) else: raise Exception() return animation @staticmethod def _parse_move_animation(figure, parts): to_x = float(parts[1]) to_y = float(parts[2]) time = float(parts[3]) cycle = len(parts) >= 5 return MoveAnimation(figure, to_x, to_y, time, cycle) @staticmethod def _parse_scale_animation(parts): destination_scale = float(parts[1]) time = float(parts[2]) cycle = len(parts) >= 4 return ScaleAnimation(destination_scale, time, cycle) @staticmethod def _parse_rotate_animation(parts): rotate_angle = float(parts[1]) time = float(parts[2]) cycle = len(parts) >= 4 return RotateAnimation(rotate_angle, time, cycle) def main(): canvas_width, canvas_height, animated_symbols = \ AnimationsParser().parse_animated_symbols('animation_path.txt') window = tkinter.Tk() configure_window_location(window, canvas_width, canvas_height) canvas = tkinter.Canvas(window, width=canvas_width, height=canvas_height) scene = Scene(canvas, animated_symbols) timer = Timer() timer.start() window.after(TIME_BETWEEN_FRAMES, scene_loop, window, scene, timer) window.mainloop() if __name__ == "__main__": main() 

C. تتريس بوت

المؤلف: ديمتري نيفدومسكي
المهلة1 ثانية
حد الذاكرة256 ميغابايت
دخولالمدخلات القياسية أو المدخلات
استنتاجالإخراج القياسي أو الإخراج
يحب Busy Arkady قضاء وقت فراغه في المشاركة في عدة مزادات لأجهزة الكمبيوتر القديمة. على واحد منهم ، رأى الكومودورو الذي رأى الحياة ، والتي سارع أركادي إلى شرائها. وفي هذه المرة ، لم يكتسب فقط الأجهزة ، ولكن أيضًا البرمجيات ، كانت هناك مفاجأة تنتظره على الكمبيوتر - كان هناك Tetris لم تنته من قبل المالك السابق. من خلال الخبرة ، كشف أركادي عن قواعده.

يتم عرض اللاعب على حقل Tetris بحجم 10 خلايا وبارتفاع غير محدود. قائمة بجميع tetramino التي يجب أن توضع في الميدان. تتساقط Tetramino على الفور ، أي ، يتم تعيين موضعها مرة واحدة للحركة المقابلة ، وخلال الخريف ، لا يمكن تغيير الموضع والدوران.

يقع Tetramino حتى يتعثر في الأسفل أو على شخصية أخرى. إذا تم ملء صف كامل من الحقل في نفس الوقت ، يختفي هذا الصف ، ويقع كل ما فوقه أعلى خلية واحدة.

يتم تحديد عدد النقاط التي تم الحصول عليها بعدد الصفوف المدمرة. تنتهي اللعبة عندما يتم وضع جميع القطع المقترحة. ترك مؤلف اللعبة وراءه جدول السجلات ، حيث أخذ هو نفسه جميع الأماكن.

كما ذكر آنفا ، أركادي هو شخص مشغول جدا. لكنه أيضا مقامرة جدا. ساعده في أن يصبح الأفضل في هذه اللعبة.

جدول الأرقام والمنعطفات المحتملة

تنسيقات I / O ، مثال ، وملاحظات

تنسيق الإدخال


بيانات الإدخال موجودة في الملفات input1.txt ، input2.txt ، ... ، input10.txt. الأرشيف مع الملفات .

يحتوي السطر الأول على عدد موجب من الأرقام N (N ≤ 100).

في كل سطر لاحق ، يتم نقل حرف لاتيني واحد من المجموعة {'O', 'S', 'Z', 'L', 'J', 'T', 'I'} .

يمثل كل رمز شكل tetramino.

تنسيق الإخراج


للتحقق ، يجب إرسال أرشيف مضغوط به ملفات الإخراج الموجودة في جذره مع أسماء output1.txt ، output2.txt ، ... ، output10.txt ، حيث يجب أن يتوافق ملف الإخراج outputX.txt مع ملف الإدخال inputX.txt.
يتكون ملف الاستجابة من خطوط N ، كل منها يتوافق مع tetramino من بيانات الإدخال ويتكون من رقمين A i و B i ، مما يشير إلى تحرك اللاعب بالشكل المقترح:

1. A تشير إلى عمود عنصر tetramino في أقصى اليسار (1 ≤ A i ≤ 10).
2. B i تشير إلى اتجاه دوران tetramino (1 ≤ B i ≤ 4).

إذا كان الملف المطلوب غير موجود في الأرشيف أو تم تكوينه بشكل غير صحيح ، فسيتم منح 0 نقطة للاختبار المقابل.

مثال

دخولاستنتاج
15
Z
O
L
O
J
S
T
J
Z
J
Z
S
Z
I
O
1 2
9 1
6 4
9 1
3 2
6 1
1 2
4 1
6 2
3 1
8 2
2 2
4 1
10 1
6 1

الملاحظات


في هذا المثال ، سيتم تدمير 4 صفوف.

الحالة النهائية للحقل:



معلومات عن رموز الخطأ:

1. PE - حدث خطأ في الإخراج (على سبيل المثال ، لا يوجد مثل هذا التناوب في الشكل)
2. WA - تم تقديم معلومات حول دوران الشكل وموضعه بشكل صحيح ، ولكن هذا الترتيب يتجاوز حدود الحقل.
3. TL ، ML ، OK ، RE - هذه الرموز لها نفس المعنى كما هو الحال في قواعد نظام Yandex.Contest.

نظرًا لأن المشكلة مكتملة NP ، لا يجب أن يكون الحل هو الأمثل من الناحية الرياضية. يتم تحديد فعالية القرار من خلال عدد النقاط التي تم تسجيلها.

قرار


هذه مهمة اختبار مفتوحة. دعونا معرفة ما يعنيه هذا.

يتلقى المشارك تحت تصرفه أرشيف مضغوط ، في جذره ، الملفات النصية input1.txt ، input2.txt ، ... ، input10.txt. ملف واحد هو مجموعة واحدة من الشخصيات tetramino التي يتعين ترتيبها. كاستجابة من المشارك ، من المتوقع أن يكون أرشيف zip الذي تم إنشاؤه ، والذي في جذره ، هو files1.txt ، output2.txt ، ... ، output10.txt. يجب أن يحتوي كل ملف على تحركات بقطاعات بنفس الترتيب المحدد به في ملف المجموعة المقابلة.

المهمة NP- كاملة والحل مئة في المئة هو البحث الشامل فقط. وبالتالي ، فإن التعقيد ينمو باطراد مع تزايد عدد الأرقام. نظرًا لأنه ليس من الضروري تسليم رمز الحل ، فلا توجد قيود عليه في الذاكرة ووقت التنفيذ.

تم إعطاء نقطة كاملة للمهمة عند تحقيق جودة "مرضية" - كان يجب أن يكون الحل قد سجل 60٪ من النقاط. سجل حل المؤلف للمشكلة بنفس القدر ، والذي كان يستند إلى خوارزمية جينية مدربة على أداة عشوائية Tetris قياسية. هذا عشوائي هو موضح في المقال .

لا تختلف بقية المهمة كثيرًا عن كتابة روبوت منتظم للتتريس ، إلا أن "كأس" الملعب غير محدود الطول. لذلك ، فإن نجاح القرار لا يتحدد بعدد الوقت الذي يمكن أن يلعبه الروبوت دون تجاوز "الزجاج" ، ولكن مدى نجاحه في ترتيب مجموعة محدودة من الشخصيات.

كان المشارك حرا في اختيار استراتيجية الحل. فيما يلي بعض منها من أجل زيادة التعقيد وزيادة عدد النقاط المسجلة:

1. نلعب "الأيدي" دون استخدام الكود ، وكتابة التحركات في الحل.
2. نكتب متخيل ولعب "الأيدي" ، وكتابة التحركات في الحل.
3. الخوارزمية الجشعة. في كل منعطف ، نحاول وضع القطعة بحيث يكون عدد الصفوف التي تم إتلافها هو الحد الأقصى. إذا كان هناك العديد من هذه الخيارات ، فحدد أي منها بشكل عشوائي.
4. نفس خوارزمية الجشع كما في الفقرة 3 ، فقط يتم التحقق ليس نجاح تحديد شخصية واحدة ، ولكن نجاح البحث الشامل لمجموعة من الشخصيات (على سبيل المثال ، مجموعة من خمسة أرقام).
5. الخوارزمية الجينية. نأخذ في الاعتبار في وظيفة اللياقة البدنية ليس فقط عدد الصفوف المكسورة ، كما هو الحال في الخوارزمية الجشعة ، ولكن أيضًا نعومة "تخفيف" الحقل ، وعلى سبيل المثال ، عدد المساحات الحرة المتكونة بين الأشكال.

D و E. كويست

المؤلفون: Ilimdar Ablyaev و Ilya Kuteev

ميشا يجعل لعبة المحمول في هذا النوع من السعي. وجد على الإنترنت مكتبة جاهزة مع محرك للعبة وصنع واجهة تعتمد عليها. ميشا في عجلة من أمرها لإطلاق اللعبة وارتكبت العديد من الأخطاء أثناء عملية التطوير. لإنهاء المشروع في الوقت المحدد ، طلبت منك ميشا المساعدة. قم بتنزيل المشروع وتصحيح أخطاء الترجمة والتعطل والأخطاء المنطقية فيه. أكمل البحث وانتقل إلى شاشة Bingo ، التي تظهر عليها العبارة السرية. هي ستكون الحل للمشكلة.

قم بتنزيل الأرشيف باستخدام المشروع: Android و iOS . تنسيق الإخراج عبارة سرية (السلسلة تصل إلى 255 حرفًا).

حل أندرويد


1) حذف السطر مع السمة أو إضافة أي سمة.

2) نذهب إلى نص المهمة ونصلح جميع الأخطاء التي يسلط عليها IDE الضوء.

  1. نزيل المعدلات النهائية من mBackButton و mTitleTextView ، حيث أن التهيئة تتطلب موارد.
  2. إذا قمت بنقل تهيئة mTitleTextView و mBackButton إلى مكان الإعلان ، فسوف يتعطل التطبيق في البداية ، لأنه ليس لديه سياق حتى الآن.
  3. نصلح الخطأ مع القيمة المرجعة للطرق - نستبدل Layout بـ ViewGroup.
  4. نقوم بتهيئة متغير okButton في طريقة getTextTaskControlsLayout.
  5. أيضا ، قد IDE تسليط الضوء على خطأ منطقي أن يتم تعيين نفس المستمعين إلى الزرين الأيسر والأيمن.

3) . ds , «java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity». .

4) .

  • — java.lang.IndexOutOfBoundsException.
  • : Layout Layout. .
  • 1.1 ( ).

5) .

  • , .
  • ( , , ).
  • . :
    — Layout.
    — .
  • .

6) . — .

7) «».

  • android.content.res.Resources$NotFoundException.
  • . , ID .
  • .

! .

iOS


. :



, Optional<Optional<Step>>. guard let Optional . Optional, flatMap({ $0 }), .



, .



, QuestCore . :



, — goLeft, goRight . , goRight .



, : TestView, firstResponder . , TestView firstResponder. , UIKit.



«». IBOutlet, , . .







, 2018 .

Source: https://habr.com/ru/post/ar482210/


All Articles