단순화 된 기차 세트


27

Brio와 같은 목재 트랙에서 실제 열차의 완벽한 작은 금속 복제품에 이르기까지 다양한 유형의 기차 세트가 존재하지만 가능한 한 많은 조각을 사용하여 이상적인 트랙을 설계해야합니다.

따라서 작업은 사용 가능한 부품을 입력하면 모든 요소를 ​​사용하여 완전한 폐쇄 회로를 구축 할 수 있는지 여부와 그렇지 않은 경우 최대 회로에서 몇 개의 부품이 남을지 결정하는 것입니다.

이것은 단순화 된 열차 세트이므로 큰 곡선, 작은 곡선 및 직선의 세 가지 요소 만 있습니다. 이들은 모두 정사각형 그리드를 기반으로합니다.

큰 곡선과 작은 곡선을 보여주는 정사각형 격자

  • "큰 곡선"은 각 차원에서 2 단위를 포함하는 90도 코너입니다.
  • "작은 곡선"은 각 방향으로 한 단위를 덮는 90도 코너입니다
  • "직선"은 1 단위 길이의 직선 요소입니다.

이것은 가능한 최소 회로가 4 개의 작은 곡선으로 구성되어 있음을 의미합니다. 그것은 반경 1 단위의 원입니다. 이것은 다양한 타원형을 형성하기 위해 직선 요소 쌍을 추가하여 확장 할 수 있습니다. 더 많은 곡선을 추가하거나 곡선 유형을 혼합하여 다른 회로가 가능합니다.

이 기차 세트에는 교차점이나 트랙이 교차하는 방법이 포함되어 있지 않으므로 두 요소가 다른 요소의 같은 끝에 연결되거나 (Y 대형이 아님) 서로 교차하는 경우 (X 대형이 아님)는 유효하지 않습니다 . 또한 기차 세트이므로 기차를 통과하지 못하는 모든 구성이 유효하지 않습니다. 예를 들어 90도 각도로 만나는 직선 (수직 직선 사이에 곡선이 있어야 함)과 90도 각도로 만나는 곡선이 포함됩니다. (곡선이 흐릅니다).

또한 유형을 무시하고 가능한 한 많은 조각을 사용하고 싶기 때문에 항상 비트 수가 더 많은 회로를 선택해야합니다. 마지막으로 하나의 트레인 만 있으므로 여러 회로를 생성하는 솔루션은 허용되지 않습니다. .

입력

사용 가능한 큰 곡선, 작은 곡선 및 직선의 수 또는 동일한 순서로 프로그램에 전달 된 매개 변수에 해당하는 모두 0보다 크거나 같은 세 개의 정수 배열입니다.

산출

제공된 요소에 대해 가능한 최대 회로가 구성 될 때 남은 조각 수에 해당하는 숫자입니다.

테스트 데이터

Minimal circuit using big curves
Input: [4,0,0]
Output: 0

Slightly more complicated circuit
Input: [3,1,2]
Output: 0

Incomplete circuit - can't join
Input: [3,0,0]
Output: 3

Incomplete circuit - can't join
Input: [3,1,1]
Output: 5

Circuit where big curves share a centre
Input: [2,2,0]
Output: 0

Bigger circuit
Input: [2,6,4]
Output: 0

Circuit where both concave and convex curves required
Input: [8,0,0] or [0,8,0]
Output: 0

Circuit with left over bit
Input: [5,0,0] or [0,5,0]
Output: 1

노트

  • 2 직선과 작은 곡선은 큰 곡선과 동일하지만 더 많은 조각을 사용하므로 선호됩니다-회로에 큰 곡선이있는 경우이 조합이 남아있는 상황이되어서는 안됩니다
  • 4 개의 작은 곡선은 일반적으로 4 개의 직선으로 교체 될 수 있지만 회로가 자체적으로 교차하는 경우에는 그렇지 않습니다
  • 기차 세트도 이상적입니다-트랙 요소가 표시된 너비를 차지하므로 커브가 교차하지 않고 단일 그리드 사각형을 통과하는 것이 유효합니다. 그리드는 단지 요소 크기를 정의합니다. 특히 두 개의 큰 곡선을 배치하여 예제 다이어그램의 왼쪽 상단에있는 그리드 정사각형이 왼쪽에서 위쪽으로 실행되는 다른 큰 곡선의 오른쪽 하단 정사각형이되도록 할 수 있습니다 (다이어그램이 오른쪽에서 아래쪽으로 실행 됨)
  • 작은 곡선은 큰 곡선 아래의 빈 공간에 맞을 수 있습니다 (위 오른쪽 그리드 사각형 위). 두 번째 큰 곡선은 또한 그 공간을 사용할 수 있으며, 첫 번째에서 하나 아래로 이동했습니다.
  • 작은 곡선은 큰 곡선의 외부와 동일한 그리드 공간에 맞지 않습니다. 대부분 불법적으로 교차하지 않는 연결 방법이 없기 때문에

출력에 따라서 [5,0,0]또는 [0,5,0]것입니다 1. 그 맞습니까? 이러한 테스트 사례를 추가 할 수 있습니까?
Arnauld

@arnauld 예, 맞습니다. 가능한 가장 긴 회로를 작성한 후 항상 나머지 요소 수 여야합니다.
Matthew

당신이 있는지 확인하시기 바랍니다 수 를위한 솔루션 [8,0,0]이 개 2 × 2 요소가 그리드의 중심에 겹쳐을?
Arnauld

예, 이것이 해당 테스트 사례에 대한 예상 솔루션입니다.
Matthew

자기 교차로가 어떻게 작동하는지 잘 모르겠습니다. 허용되는 것과 금지 된 것을 정의 할 때 더 명확하게 설명해 주시겠습니까?
밀 마법사

답변:


9

[JavaScript (Node.js)], 1220 바이트

f=r=>{var a=[{n:0,d:[[0,-1,"0000000101011"],[1,-1,"0011111111111"],[0,0,"0111101111111"],[1,0,"1100010000000"]],e:[2,-1,1]},{n:0,d:[[-1,-1,"1001111111111"],[0,-1,"0000010010110"],[-1,0,"0110000100000"],[0,0,"1101111011111"]],e:[-2,-1,3]},{n:1,d:[[0,0,"0011101111111"]],e:[1,0,1]},{n:1,d:[[0,0,"1001111011111"]],e:[-1,0,3]},{n:2,d:[[0,0,"1111101011111"]],e:[0,-1,0]}],e=r=>{var a=r.d,e=r.e,n=[];return a.forEach(r=>{var a=r[2];n.push([-r[1],r[0],""+a[10]+a[5]+a[0]+a[8]+a[3]+a[11]+a[6]+a[1]+a[9]+a[4]+a[12]+a[7]+a[2]])}),{d:n,e:[-e[1],e[0],e[2]]}};i=((r,a)=>{for(var n=0;n<r.d;n++,a=e(a));var p=!1;return a.d.forEach(a=>{var e=r[`${r.p.x+a[0]},${r.p.y+a[1]}`];void 0===e&&(e="00000000000000");for(var n="",d=0;d<13;d++)"1"===e[d]&&"1"===a[2][d]&&(p=!0),n+=e[d]===a[2][d]?e[d]:"1";r[`${r.p.x+a[0]},${r.p.y+a[1]}`]=n}),r.p.x+=a.e[0],r.p.y+=a.e[1],r.d=(r.d+a.e[2])%4,!p});var n=[],p=(r,e)=>{a.forEach(a=>{var d=Object.assign({},r);if(d.p=Object.assign({},r.p),!(e[a.n]<=0)&&i(d,a)){if(d.ps+=a.n,0==d.p.x&&0==d.p.y&&0==d.d)return void n.push(d);var s=Object.assign([],e);s[a.n]-=1,p(d,s)}})};p({p:{x:0,y:0},d:0,ps:""},Object.assign([],r));var d=0;n.forEach(r=>{r.ps.length>d&&(d=r.ps.length)}),console.log(r[0]+r[1]+r[2]-d)};

온라인으로 사용해보십시오!

참고 : 입력은 실제로 시작시 변수 q입니다. [2,6,4]는 최적화가없는 무차별 대입 솔루션이기 때문에 시간이 다소 걸립니다.

실제로 1 년 이상 대답하지 않았기 때문에 실제로이 작업을 수행했으며 가능한 경우 다소 궁금했습니다.


원본 코드 :

var q = [4, 2, 4];
var t = [
    {
        n: 0,
        d: [
            [0, -1, "0000000101011"],
            [1, -1, "0011111111111"],
            [0, 0, "0111101111111"],
            [1, 0, "1100010000000"]
        ],
        e: [2, -1, 1],

    },
    {
        n: 0,
        d: [
            [-1, -1, "1001111111111"],
            [0, -1, "0000010010110"],
            [-1, 0, "0110000100000"],
            [0, 0, "1101111011111"]
        ],
        e: [-2, -1, 3]
    },
    {
        n: 1,
        d: [
            [0, 0, "0011101111111"]
        ],
        e: [1, 0, 1]
    },
    {
        n: 1,
        d: [
            [0, 0, "1001111011111"]
        ],
        e: [-1, 0, 3]
    },
    {
        n: 2,
        d: [
            [0, 0, "1111101011111"]
        ],
        e: [0, -1, 0]
    },
];

r = (p) => {
    var d = p.d; var e = p.e; var o = [];
    d.forEach(i => {
        var d = i[2];
        o.push([-i[1], i[0], "" + d[10] + d[5] + d[0] + d[8] + d[3] + d[11] + d[6] + d[1] + d[9] + d[4] + d[12] + d[7] + d[2]])
    });
    return { d: o, e: [-e[1], e[0], e[2]] };
};

i = (g, p) => {
    //console.log(g.p, g.d);
    for (var i = 0; i < g.d; i++ , p = r(p));
    var c = false;
    p.d.forEach(d => {
        var v = g[`${g.p.x + d[0]},${g.p.y + d[1]}`];
        if (v === undefined) v = "00000000000000";
        var o = "";
        for (var i = 0; i < 13; i++) {
            if (v[i] === '1' && d[2][i] === '1')
                c = true;
            o += (v[i] === d[2][i]) ? v[i] : '1';
        }
        //console.log(o);
        g[`${g.p.x + d[0]},${g.p.y + d[1]}`] = o;
    });
    g.p.x += p.e[0];
    g.p.y += p.e[1];
    g.d = (g.d + p.e[2]) % 4;
    return !c;
};

var l = [];
var re = (g, p) => {
    t.forEach(piece => {
        var gr = Object.assign({}, g);
        gr.p = Object.assign({}, g.p);
        if (p[piece.n] <= 0)
            return;
        if (i(gr, piece)) {
            gr.ps += piece.n;
            if (gr.p.x == 0 && gr.p.y == 0 && gr.d == 0) {
                l.push(gr);
                return;
            }
            var ti = Object.assign([], p);
            ti[piece.n] -= 1;
            re(gr, ti);
        }
    });
};
var gr = { p: { x: 0, y: 0 }, d: 0, ps: "" };
re(gr, Object.assign([], q));

var c = 0;
var lo = 0;
l.forEach(g => {
    if (g.ps.length > lo) {
        require("./draw.js")(g, `outs/out${c++}.png`)
        lo = g.ps.length;
    }
});

console.log(q[0] + q[1] + q[2] - lo);

먼저 사용한 타일 그래픽을 포함시켜야합니다.

사용 된 타일

The sections of this tile were given a number and
used for comparison and overlap handling later.

So there first thing is the array t at the start. 
This is a collection of track pieces that contain
    n[ame]: the index of the input array.
    d[ata]: the offset from the current tile and the Tile bit values.
    e[nd]: the relative offset and rotation that the piece provides.

function r[otate] ( p[iece] )
    this outputs a piece that is rotated by 90 degrees
    by rearranging the tile bits and the end offset

function i[nsert] ( g[rid], p[iece] )
    this modifies the passed in grid trying to place down each tile of the piece.
    if it hits a point where 2 tiles intersect it sets a flag c[ollision]
    it then adjusts the current p[osition] and and d[irection] stored in the grid.
    then it returns !c[ollision]

function re[peat] ( g[rid], p[eices] )
    this iterates across all nodes which
        creates a copy of the g[rid] as gr[id].
        checks if the piece is available if not continue
        if the peice is added without a collision
            add piece name to gr[id].ps[piece string];
            it checks if its back at the start
                add gr[id] to l[ist]
                return as no more pieces can be added without a collision.
            clone peices remove the used peice ti[nput]
            call re[peate] (gr[id], ti[nput])

call re[peate] with empty grid

search l[ist] for longest piece string
and output input added together minus the length of the longest string.

쓰기가 어렵다면 죄송하지만 코드 작동 방식을 설명하는 데 익숙하지 않습니다.

추신 : 나는 실제로지도를 PNG로 그리는 데 몇 가지 기능을 만들었지 만 물론 공간을 절약하기 위해 제거되었습니다.


나는 감동했다-나는 이것에 대한 희망을 포기했다! 글쓰기에 관심이 있으
Matthew

@ Matthew 내가 쓸 시간이되면 볼 수 있습니다. 실제로 약간의 시간이 걸릴 수 있습니다. 그러나 네, 일반적으로 이것들은 제가 좋아하는 퍼즐입니다. 짧지 않더라도 가능하다는 것을 증명하는 것이 재미 있습니다.
Cieric

@Matthew가 쓰기를 추가했습니다.
Cieric

p[a.n]-=1대신에 사용하기로 선택한 이유 가 p[a.n]--있습니까?
Jonathan Frech

q그렇게 초기화 하는 것은 허용되는 입력 방법 이 아닙니다 . 가장 일반적으로 함수 인수로 만들거나 stdin에서 읽습니다.
Ørjan Johansen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.