Найти конфигурацию зеркала, соответствующую лазерным направлениям


13

ОБНОВЛЕННАЯ ОЦЕНКА : Поскольку эта задача сложнее, чем я ожидал, я скорректировал оценку. Программа, которая может решить один зеркальный ввод, является правильным ответом. Более сложные программы получают бонус к своему счету.

На PPCG было несколько загадок, чтобы найти лазерный путь в коробке с зеркалами. В этой головоломке вам нужно создать коробку зеркал, чтобы соответствовать целому ряду лазерных направлений.

Вам предоставляется окно и спецификации, где лазеры должны входить и выходить. Ваша программа должна разместить ровно N двухсторонних зеркал в коробке, чтобы соответствовать спецификации. Зеркала должны быть наклонены под углом 45 градусов, но могут быть наклонными вперед или назад.

вход

Ваша программа должна принять блочную сетку через STDIN, аргумент командной строки или файл в следующих примерах формата:

+--G--+     +abcde+
G     |     f/////d
|    /|     a//   c
+-----+     f     |
            +-b-e-+

Буквенные пары (можно использовать [a-zA-Z]) указывают на вход / выход до 52 лазеров. Внутри коробки будет N /зеркал. Размеры поля будут 3 <= W, H <= 200. Поле состоит из +|-символов. В коробке может быть любое количество зеркал, включая ноль.

Выход

Вывод должен соответствовать вводу, за исключением того, что /символы могут быть перемещены и / или изменены на \символы. Ваша программа должна отправлять правильную строку зеркального окна в STDOUT или в файл, после новой строки необязательно. Если никакое размещение зеркал не может соответствовать входной спецификации, выведите Impossible\n. Примеры возможных решений:

+--G--+     +abcde+
G  /  |     f \ \ d
|     |     a/ \  c
+-----+     f / //|
            +-b-e-+

Пример тестирования

Входные данные:

+abcdefghijklmnopqrstuvwxyA-+
|///////////////            |
|///////////////            |
|                           |
+-Abcdefghijklmnopqrstuvwxya+

Пример вывода:

+abcdefghijklmnopqrstuvwxyA-+
|\                         \|
|/                        / |
|\\\\\\\\\\\\\\\\\\\\\\\\\\ |
+-Abcdefghijklmnopqrstuvwxya+

Подсчет очков (ОБНОВЛЕНО)

Это код-гольф с бонусами. Вы должны указать своим ответом, сколько зеркал может решить ваша программа (N). Ваша оценка - это длина вашей программы в байтах, деленная на N. Это позволяет людям войти с простой программой, но вознаграждает больше амбициозных программистов бонусом.

Стандартные лазейки запрещены.


3
Это звучит как тяжелая проблема, независимо от игры в гольф.
Orlp

2
Подсказка: грубая сила не вариант ; для более крупного примера вам понадобится 3 возраста вселенной со скоростью 10 000 вариантов в секунду.
Sanchises

@sanchises Я думаю, это займет намного больше времени, так как любое зеркало можно перевернуть, поэтому я думаю, что вам также нужен * 2^30компонент там
VisualMelon

Дополнительный совет: вам нужно будет использовать свойства головоломки, чтобы сократить пространство поиска. Вы также можете использовать комбинации частичных решений или переходы от частичных решений, близких к полному решению. Теперь можно ответить более простыми решениями, поэтому программы, которые решают одну или две зеркальные головоломки, также приветствуются.
Логика Найт

Ответы:


2

C # - 897 862 байта

Нашел серьезную ошибку при размещении зеркал там, где их не может быть. Теперь это работает, надеюсь! Также немного поиграл в гольф, не мог оставить там время пока ... позорно.

Завершить программу, принимает входные данные из STDIN, выводит в STDOUT.

Это было очень весело, оно отлично справляется с проблемой 7 на 5 (а когда вы убираете одно из зеркал, что делает это невозможным), решение проблемы 30 на 5 заняло около 1 часа.

using Q=System.Console;class P{static int w,L;static string S(char[]M,int t,int r,int i,int d,int[]B){var s="";if(r<0)return s;M=(char[])M.Clone();B=(int[])B.Clone();B[i]=1;for(i+=d;M[t]<48|t==i;i=t+(d=t<w?w:t>L-w?-w:t%w<1?1:-1))if(++t>=L){for(i=0;++i<L&r>0;)if(B[i]<1&M[i]<33){M[i]='.';r--;}return r<1?new string(M):s;}int c=M[i];if(c>32)s=c>47|c<46?s=c==M[t]?S(M,t,r,t,0,B):s:S(M,t,r,i,c<47?w/d:-w/d,B);else if((s=S(M,t,r,i,d,B))==""&B[i]<1){M[i]='.';s=S(M,t,r-1,i,w/d,B);if(s==""){M[i]='/';s=S(M,t,r-1,i,-w/d,B);}}return s;}static void Main(){string a,A="",R=A;for(;(a=Q.ReadLine())!=null;A+=a)L+=(w=a.Length);var G=A.ToCharArray();int r=0,i=L;for(;i>0;G[i]=G[i]=='|'?',':G[i])if(G[--i]==47|G[i]==92){r++;G[i]=' ';}a=S(G,0,r,1,w,new int[L]);if(a=="")R="Impossible\n";else for(;i<L;i+=w)R+=a.Substring(i,w)+"\n";Q.Write(R.Replace(".","\\").Replace(",","|"));}}

Пример 7 на 5:

+abcde+
f/////d
a//   c
f     |
+-b-e-+

+abcde+
f   \ d
a/  //c
f/ \ /|
+-b-e-+

Невозможная версия:

+abcde+
f ////d
a//   c
f     |
+-b-e-+

Impossible

Что-то другое (программа не смотрит на оригинальное зеркальное отображение):

+a----+
|//// |
|/////|
|/////|
+----a+

+a----+
| /\\\|
|\\\\\|
|\\/\\|
+----a+

Решение 30 на 5:

+abcdefghijklmnopqrstuvwxyA-+
| \\\\\\\\\\\\\\\\\\\\\\\\ \|
| /                       //|
|\                         \|
+-Abcdefghijklmnopqrstuvwxya+

Он по очереди смотрит на каждый лазерный источник и строит для него действительный маршрут (если может), а затем переходит к следующему. Это довольно простой поиск в глубину, который должен знать, на какой лазерный источник (цель) он смотрит, сколько зеркал осталось для него разместить, текущую ячейку, в которой он находится, направление, в котором он движется, и каждую ячейку. это уже посещено (так, чтобы это не помещало зеркало, где это уже было). Последние 3 используются для сборки пути для текущей цели и при сбросе при изменении цели. Как только все лазеры подключены, он идет вперед и заполняет все пробелы, которые ему не нужны, оставляя пустыми (еще одна причина, по которой он должен знать, где бы он ни был).

Когда он строит маршруты, он предпочитает идти «вперед», а не вставлять зеркало, а когда он это делает, он предпочитает «\» зеркало - это лучше всего видно в примере «что-то другое» выше, где он пропускает первую ячейку ниже top-most 'a', затем непрерывно заполняет "\", если он может найти решение с одним, в противном случае - "/" (естественно, если пропуск первой ячейки привел к невозможности найти решение, то он вернитесь и попробуйте вместо этого поставить зеркало).

using Q=System.Console;

class P
{
    static int w,L;

    // M is cur grid
    // t is target edge thing (0->L)
    // r is mirrors remaining
    // i is pos
    // d is dir
    static string S(char[]M,int t,int r,int i,int d,int[]B)
    {
        var s="";

        if(r<0) // no mirrors left
            return s;

        // clone everything
        M=(char[])M.Clone();
        B=(int[])B.Clone();

        B[i]=1; // can't write to this

        for(i+=d; // move i
            M[t]<48|t==i; // only if target is something sensible (increment if i==t)
            i=t+(d=t<w?w:t>L-w?-w:t%w<1?1:-1)) // reflect, should be fine for w=3
            if(++t>=L) // run off the end
            {
                for(i=0;++i<L&r>0;) // don't need I any more (count through everything)
                    if(B[i]<1&M[i]<33) // not been here & it's open space
                    {
                        M[i]='.'; // doesn't matter
                        r--;
                    }
                return r<1?new string(M):s; // none remaining ? victory : defeat
            }

        int c=M[i];
        if(c>32) // not boring
            s=c>47|c<46? // hit edge
                s=c==M[t]? // hit the correct thing
                    S(M,t,r,t,0,B): // i+0=t, tells it to increment t
                    s
            :S(M,t,r,i,c<47?w/d:-w/d,B); // mirror
        else // boring
            if((s=S(M,t,r,i,d,B))==""&B[i]<1) // fwd
            {
                M[i]='.'; // use . instead of \
                s=S(M,t,r-1,i,w/d,B); // \
                if(s=="")
                {
                    M[i]='/';
                    s=S(M,t,r-1,i,-w/d,B); // /
                }
            }

        return s;
    }

    static void Main()
    {
        string a,A="",R=A; // R is free
        for(;(a=Q.ReadLine())!=null;A+=a) // read input
            L+=(w=a.Length); // note width, accumulate length

        var G=A.ToCharArray();

        int r=0,i=L; // count mirrors (I refuse to make these static)
        for(;i>0; // end on i=0
            G[i]=G[i]=='|'?',':G[i]) // replace | with ,
            if(G[--i]==47|G[i]==92) // remove and count mirrors
            {
                r++;
                G[i]=' '; // storing G[i] doesn't seem to save anything
            }

        // search
        a=S(G,0,r,1,w,new int[L]);

        if(a=="") // defeat
            R="Impossible\n";
        else // victory
            for(;i<L;i+=w) // for each line
                R+=a.Substring(i,w)+"\n";

        Q.Write(R.Replace(".","\\").Replace(",","|")); // swap back | and \
    }
}

Хорошее решение. Согласно новой системе подсчета очков, вы набрали не менее 917/7 = 131.
Logic Knight

2

Python, 671 654 байта

Не решение, а попытка, читайте ниже.

import random as R
def V(F):
 for S,_x,_y in (F[0],0,1),(F[-1],0,-1),([L[0] for L in F],1,0),([L[-1] for L in F],-1,0):
  for i,C in enumerate(S):
   if not C in '+-|':
    x=_x;y=_y
    if not x: X=i;Y=y
    elif not y: Y=i;X=x
    while F[Y][X] != C:
     if F[Y][X]=='\\':x,y=y,x
     if F[Y][X]=='/':a=x+y;x,y=x-a,y-a
     X+=x;Y+=y
     try:
      if F[Y][X] in '+-|':return False
     except:
      return False
 return True
F=open(input()).read().split('\n')
while 1:
 _=[F[0]]+['\n'.join([L[0]+''.join([R.choice(' \\/')for i in range(len(F[0])-2)])+L[-1] for L in F[1:-1]])]+[F[-1]]
 if V(_):
  for l in _: print l
  break

Я не играл в гольф по максимуму, так как я не удовлетворен решением. Vпроверяет данное решение, обходя поле Fдля каждого найденного символа Cв боковой линии. Решения генерируются случайным образом. Это некрасиво, это работает для entry1, но занимает много времени для других записей. Поскольку он случайным образом пытается найти решение, я не считаю это реальным решением данной проблемы; но это может помочь другим.

Бегать: echo "entry1.txt" | python script.py


1
С новой системой подсчета очков это правильное решение, но оно не дает бонус делителя (если только он не может решить проблемы с 2 или более зеркалами). Я думаю, что вы могли бы оптимизировать это, обрезав недопустимые конфигурации ранее (например: каждый столбец или строка с буквой на краю должны иметь хотя бы одно зеркало - если только совпадающие буквы не противоположны друг другу).
Логика Найт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.