拯救大雁免于灭绝


13

被称为Alex A的鹅种以其居于由64个单元格组成的三角形网格中而闻名:

细胞
(图片来自这个无关的欧拉项目问题。)

我们将用数字标记每个单元格,0使其63从第一行开始,然后在其下方的每一行中从左向右移动。因此,顶部的单元格是0,而右下角的单元格是63

每个单元都有三个边界。我们可以在表格a,b中标记每个边框,其中ab是共享该边框的单元格的编号。例如,单元格0和之间的边界2将被称为0,22,0(将它们置于哪个顺序都没有关系)。

网格最边缘的边框的标记系统是不同的,因为网格边缘的单元格具有不与其他单元格共享的边界。如果边框只是一个单元格的一部分,我们将使用字母X。例如,小区的三个边框00,20,X0,X

一些细胞含有。但是,如果您不保护它们,这些鹅将会被邪恶的狐狸杀死(来自网格外部)。如果所有的鹅都死了,那么BrainSteel会很难过。因此,我们将编写一个程序在鹅周围建起篱笆,以保护它们免受狐狸侵害。鹅应该存在于单个完全封闭的栅栏多边形中。我们的围栏预算很低,因此请使用尽可能少的围栏。

输入说明

0到的逗号分隔的数字列表63,代表包含鹅的细胞。例:

6,12

输出说明

为了成功保护鹅,需要在其上建立围栏的边界列表。这应该是最小数量的围栏。例:

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

“鹅应该存在于完全封闭的栅栏多边形中。” 所有的鹅都必须生活在同一个多边形中,或者可能有多个(或0个)多边形?
feersum

@feersum所有的鹅应该生活在同一个多边形中。我已对问题进行了编辑以使其清楚。
2015年

@Katya多边形可以有自相交或零宽度的截面吗?像沙漏形状一样思考。
orlp 2015年

@orlp什么是零宽度部分?
2015年

2
@orlp多边形不应包含零宽度的部分。
2015年

Answers:


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坐标,然后找到每个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”。

示例解决方案(从三个角刚好进入鹅的细胞):

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 2015年

@ LegionMammal978实际上,他这样做有两个好处。.他仅将其用于Q.Write和Q.ReadLine。这些,再加上他现在使用的using语句using Q=System.Console;Q.Write();Q.ReadLine()(45字节)与您的建议using System;Console.Write();Console.ReadLine()(47字节)。
卡德2015年

此外,您还可以通过不不必要初始化下降10个字节ixyz,和p0
LegionMammal978

@ LegionMammal978您确定吗?我试过了,使用未分配的可变项会出错。
卡德2015年

@ Vioz-哪些变量?带注释的版本的哪几行?
LegionMammal978
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.