絶滅からガチョウを救う


13

アレックスAとして知られるガチョウの種は、64個のセルで構成される三角形のグリッドに存在することが知られています。

細胞
(この無関係なプロジェクトオイラー問題から撮影した写真。)

各セルに番号0をラベル付け63し、一番上の行から始めて、その下の各行を左から右に移動します。したがって、上のセルはで0あり、右下のセルは63です。

各セルには3つの境界線があります。フォーム内の各境界線にラベルを付けることができますa,baおよびbは、その境界線を共有するセルの番号です。たとえば、セル0との境界線2が呼び出される0,2か、2,0(どの順序で配置してもかまいません)。

グリッドの端のセルには他のセルと共有しない境界があるため、グリッドの端の境界のラベル付けシステムは異なります。境界線が1つのセルの一部のみである場合、文字を使用しXます。例えば、セルの3つの境界が0あり0,20,X0,X

一部のセルにはガチョウが含まれています。しかし、これらのガチョウは、あなたがそれらを保護しないと、邪悪なキツネ(グリッドの境界の外側から来る)によって殺されます。そして、すべてのガチョウが死ぬと、BrainSteelは悲しくなります。そのため、ガチョウを保護するためにガチョウの周りにフェンスを構築するプログラムを作成します。ガチョウは、フェンスで囲まれた単一の完全に囲まれたポリゴンに存在する必要があります。フェンスの予算は非常に低いため、可能な限り少ない数のフェンスを使用してください。

入力の説明

ガチョウを含むセルを表す、カンマ区切りの0to からの数字のリスト63。例:

6,12

出力の説明

ガチョウを正常に保護するためにフェンスを構築する必要がある国境のリスト。これは、可能な限り最小のフェンスにする必要があります。例:

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

「ガチョウは完全に囲まれたフェンスの多角形に存在するはずです。」すべてのガチョウは同じポリゴンに住んでいる必要がありますか、それとも複数(または0)のポリゴンがある可能性がありますか?
feersum

@feersumすべてのガチョウは同じポリゴンに住んでいるはずです。質問を編集して明確にしました。
アブサン

@Katyaポリゴンに自己交差または幅ゼロのセクションがありますか?砂時計の形のように考えてください。
orlp

@orlpゼロ幅セクションとは何ですか?
アブサン

2
@orlpポリゴンには、幅がゼロのセクションを含めることはできません。
アブサン

回答:


10

C#、530バイト

完全なC#プログラムは、入力をSTDINから1行として受け取り、末尾に「」を付けて1行を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座標に変換し、各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は含まれないことに注意してください。yについては、何も変更する必要はありませんが、隣のセルが「X」であるかどうかを検出するために「三角形」の境界チェックを実行する必要があるため、コードは少し複雑です。

解決策の例(3つのコーナーからガチョウが入ったセル):

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は、実際には2つのことをしています。彼はQ.WriteとQ.ReadLineにのみ使用しています。それらに加えて、彼が現在持っているusingステートメントはusing Q=System.Console;Q.Write();Q.ReadLine()(45バイト)対あなたの提案using System;Console.Write();Console.ReadLine()(47バイト)です。
ケード

また、あなたは不初期化しないで10バイトをドロップすることができixyz、およびp0に
LegionMammal978

@ LegionMammal978よろしいですか?私はそれを試しましたが、割り当てられていない変数を使用するとエラーが発生します。
ade

@ Vioz-どの変数ですか?注釈付きバージョンのどの行ですか?
LegionMammal978
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.