C # -897 862 바이트
거울을 놓을 수없는 곳에 심각한 버그가 있음을 발견했습니다. 이제 잘 작동합니다! 또한 약간의 가벼운 골프를 쳤다, 거기에서 while 루프를 떠날 수 없었다. .. 부끄러운.
완전한 프로그램은 STDIN에서 입력을 받아 STDOUT으로 출력합니다.
이것은 많은 재미였습니다 .7 x 5 문제에 잘 대처하고 (거울 중 하나를 제거하면 불가능 해집니다) 30 x 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(",","|"));}}
7x5 예 :
+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 x 5 솔루션 :
+abcdefghijklmnopqrstuvwxyA-+
| \\\\\\\\\\\\\\\\\\\\\\\\ \|
| / //|
|\ \|
+-Abcdefghijklmnopqrstuvwxya+
각 레이저 소스를 차례로보고 유효한 경로를 만들고 (가능한 경우) 다음 경로로 이동합니다. 보고있는 레이저 소스 (대상), 배치 할 미러 수, "현재"셀, 이동 방향 및 각 셀을 알아야하는 매우 간단한 깊이 우선 검색입니다. 이미 방문했습니다 (이미 어딘가에 거울을 두지 않습니다). 마지막 3 개는 현재 대상의 경로를 조립하는 데 사용되며 대상이 변경 될 때 재설정됩니다. 일단 모든 레이저가 연결되면, 계속해서 비워 둘 필요가없는 틈새를 채 웁니다 (방문하는 모든 곳을 알아야하는 또 다른 이유).
루트를 구축 할 때 미러를 삽입하는 것보다 "앞으로"진행하는 것이 좋으며, 그렇게 할 때는 "\"미러를 선호합니다. 위의 "다른 것"예에서 가장 잘 보입니다. 아래의 첫 번째 셀을 건너 뜁니다. 최상위 '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 \
}
}