C#-897 862バイト
ミラーを配置できない深刻なバグを発見しました。うまくいけばうまくいきます!また、軽いゴルフもしましたが、whileループをそこに残せませんでした...
完全なプログラム。STDINから入力を受け取り、STDOUTに出力します。
これは非常に楽しかったです。7x 5の問題に対処し(ミラーの1つを削除すると不可能になる)、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(",","|"));}}
7 x 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 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 \
}
}