Врятуйте гусей від вимирання


13

Види гусей, відомі як Алекс А , відомі тим, що проживають в трикутних сітках, що складаються з 64 клітин:

Клітини
(Знімок, зроблений із цієї непов'язаної проблеми проекту Euler .)

Ми будемо маркувати кожну клітинку з номерами , 0щоб 63починаючи з верхнього ряду , а потім рухаючись зліва направо в кожному рядку нижче цього. Отже, верхня клітина є, 0а нижня права клітина 63.

Кожна клітина має три межі. Ми можемо позначити кожну межу у формі, a,bде aі bє числа комірок, які поділяють цю межу. Наприклад, межа між клітинками 0і 2буде викликана ( 0,2або 2,0не має значення, в якому порядку ви їх введете).

Система маркування меж на самому краю сітки є різною, оскільки комірки на краю сітки мають рамку, яку вони не поділяють з іншими осередками. Якщо межа є лише частиною однієї комірки, ми будемо використовувати букву X. Наприклад, три кордони осередки 0є 0,2, 0,Xі 0,X.

Деякі клітини містять гусей . Однак цих гусей будуть вбиті злі лисиці (які виходять за межі сітки), якщо ви не захистите їх. І якщо всі гуси загинуть, то BrainSteel буде сумно. Тому ми напишемо програму, яка будує паркани навколо гусей, щоб захистити їх від лисиць. Гуси повинні існувати в єдиному повністю закритому багатокутнику огорож. Наш бюджет забору досить низький, тому використовуйте найменшу кількість заборів.

Опис вводу

Список чисел, розділених комами, від 0до 63, що представляють клітини, що містять гусей. Приклад:

6,12

Опис виходу

Перелік кордонів, які повинні мати на них огорожі, щоб успішно захищати гусей. Це має бути найменша кількість можливих огорож. Приклад:

5,6 6,7 11,12 12,13 

"Гуси повинні існувати у повністю закритому багатокутнику парканів". Чи повинні всі гуси жити в одному полігоні, чи може бути кілька (або 0) багатокутників?
feersum

@feersum Усі гуси повинні жити в одному полігоні. Я відредагував це питання, щоб дати зрозуміти.
абсент

@Katya Чи може багатокутник мати перехрестя або перерізи нульової ширини? Думайте, як форма пісочного годинника.
orlp

@orlp Що таке розділ нульової ширини?
абсент

2
@orlp Багатокутник не повинен містити розділів нульової ширини.
абсент

Відповіді:


10

C #, 530 байт

Повна програма C #, приймає вхід як STDIN в якості одного рядка і виводить один рядок в STDOUT, з заднім числом "".

Це досить довго ... і є занадто багато повторень x / y / z, але я досі не зміг звести це до чогось розумного, і скласти іспит за 2 години, можливо, повернуться до цього завтра.

using Q=System.Console;class P{static void Main(){int q=9,w=0,e=9,r=0,t=9,u=0,i=0,x=0,y=0,z=0,p=0;System.Action V=()=>{z=(int)System.Math.Sqrt(i);p=(x=i-z*z)%2;x/=2;y=(++z*z--+~i)/2;},W=()=>{Q.Write(i+","+(x<0|y++<0|z>7?"X":""+(z*z+2*x+1-p))+" ");};foreach(var g in Q.ReadLine().Split(',')){i=int.Parse(g);V();q=q>x?x:q;w=w<x?x:w;e=e>y?y:e;r=r<y?y:r;t=t>z?z:t;u=u<z?z:u;}for(i=64;i-->0;){V();if(!(x<q|x>w|y<e|y>r|z<t|z>u))if(p>0){if(y==r)W();if(x++==w)W();x--;if(z--==t)W();}else{if(y--==e)W();if(x--==q)W();x++;if(z++==u)W();}}}}

Ця діаграма пояснює більшість того, що відбувається.

Сітка описана як x / y / z / (p), показуючи приклад рішення

Визнайте, що через те, що ми не можемо мати секції 0-ширини, "шестикутник" завжди буде найдешевшою формою (і має перевагу надавати гусям максимум місця для пересування).

Програма працює, спочатку переводячи всі індекси вхідних комірок у x / y / z координати та знаходячи min / max кожного з x / y / z.

z = floor(root(i))
x = floor((i - z^2) / 2)
y = floor((z+1)^2 - i - 1) / 2)
p = (i - z^2) % 2

Далі він проходить кожен індекс клітинки та перевіряє, чи відповідає він описаному нами шестикутнику. Якщо це так, він перевіряє, чи є він на будь-якому з крайніх країв меж (тобто x = xmin, або y = ymax) і додає відповідні ребра, якщо вони є. Він повинен опрацювати індекс краю, який знаходиться поруч. Для x і z ми просто збільшуємо / зменшуємо їх, скільки хочемо, а потім використовуємо таку формулу:

i = z^2 + 2*x + (1-p)

Зауважте, що "паритет" завжди змінюється, і що y не бере участь. Так, нам не потрібно нічого змінювати, але код трохи заплутався, оскільки він повинен виконувати "трикутникові" межі, перевіряючи, щоб виявити, чи має сусідня комірка "X" чи ні.

Приклад розчину (клітини з гусей прямо з трьох куточків):

Input
2,50,62

Output
62,63 61,X 59,X 57,X 55,X 53,X 51,X 50,49 48,X 36,X 35,X 25,X 24,X 16,X 15,X 9,X 8,X 4,X 3,X 2,0 1,X 

Код Тідьє з коментарями:

using Q=System.Console;

class P
{
    static void Main()
    {
        int q=9,w=0,e=9,r=0,t=9,u=0, // min/max x/y/z/ (init min high, and max low)
        i=0, // index of cell we are looking at
        x=0,y=0,z=0,p=0; // x,y,z dimension

        System.Action V=()=>
            { // translates the index into x/y/z/p
                z=(int)System.Math.Sqrt(i);
                p=(x=i-z*z)%2; // 'parity'
                x/=2; // see p assignment
                y=(++z*z--+~i)/2; // ~i == -i - 1
            },
            W=()=>
            { // writes out the edge of i, and the cell described by x/z/inverse of p   (the inversion of p handles y +/-)
                Q.Write(i+","+ // write out the edge
                        (x<0|y++<0|z>7?"X":""+(z*z+2*x+1-p)) // either X (if we go out of 'trianlge' bounds), or we translate x/z/inverse of p into an index
                        +" "); // leaves a trailing space (as shown in example output)
            };

        foreach(var g in Q.ReadLine().Split(',')) // for each cell with geese
        {
            i=int.Parse(g); // grab index of cell
            V(); // compute x/y/z/p
            q=q>x?x:q; // sort out mins/maxes
            w=w<x?x:w;
            e=e>y?y:e;
            r=r<y?y:r;
            t=t>z?z:t;
            u=u<z?z:u;

            // code like the above suggests a solution with a couple of arrays would be better...
            // I've not had success with that yet, but maybe in a couple of days I will try again
        }

        for(i=64;i-->0;) // for each cell
        {
            V(); // compute x/y/z/p
            if(!(x<q|x>w|y<e|y>r|z<t|z>u)) // if we are inside the 'hex' bounds
                if(p>0)
                { // x max, y max, z min
                    // these checks check that we are on the extremes of the 'hex' bounds,
                    // and set up the appropriate vars for W calls to put the edges in
                    // must do y first, because W modifies it for us (saves 2 bytes in the next block)
                    if(y==r) // don't need the ++ (can't go out of 'trianlge' bounds)
                        W();
                    if(x++==w)
                        W();
                    x--;
                    if(z--==t)
                        W();
                    //z++; not used again
                }
                else
                { // x min, y min, z max
                    if(y--==e) // do need the -- (used for 'trianlge' bounds checking)
                        W();
                    // y is reset in W, as such
                    if(x--==q)
                        W();
                    x++;
                    if(z++==u)
                        W();
                    //z--; not used again
                }
        }
    }
}

Ви можете зберегти байт за допомогою using System;.
LegionMammal978

@ LegionMammal978 інфакт він отримує два, роблячи це .. Він використовує його лише для Q.Write та Q.ReadLine. це, плюс використовувану операцію, яку він має зараз, становить using Q=System.Console;Q.Write();Q.ReadLine()(45 байт) проти вашої пропозиції using System;Console.Write();Console.ReadLine()(47 байт).
Каде

Крім того , ви можете відмовитися від 10 байт, не без необхідності ініціалізації i, x, y, z, і p0.
LegionMammal978

@ LegionMammal978 ви впевнені? Я спробував це, і це дає помилки для використання непризначеного дозволеного.
Каде

@ Vioz- Які змінні? Які рядки в анотованій версії?
LegionMammal978
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.