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 \
}
}