どう書く第16回問題と、同じ出題者の類題CodeIQ(境界線の長さ)の解答です。
どう書く第16回問題
問題はこちら
http://nabetani.sakura.ne.jp/hena/ord16boseg/
最初Juliaで解きました。
隣の升を比較するのに、bit演算や加減算もありますが、
Juliaでは10進数をn進数の文字列に変換する機能がありますので、文字の異同で比較します。
まず'0'で埋めた7x7の配列sqを作り、8進数を2進数の文字列に変換し、該当の升に入れます。
線分の長さごとの数を入れる配列ansを用意します。ans[i]に長さiの線分の数をいれます。
長さの変数の初期値を0にし、隣の升の文字を比較し、違えば、値を1増やし、次に行きます。
隣の文字が同じなら、変数の値が0でなければその数に該当するansの値を1増やし、
変数の値を0にして次に行きます。最後の列の升は同じ文字'0'になるようにしてあります。
これを縦横それぞれ5回ずつ繰り返し、合計を答えとします。
# Julia v 1.0,1.4
str="0 060276724276 6,2,1,1,0,1
1 770175454177 2,3,0,3,1,0
2 743733377170 9,3,1,0,0,0
3 724212121273 5,2,1,1,1,1
4 100000000000 3,0,0,0,0,0
5 000002000000 4,0,0,0,0,0
6 003622223600 0,4,0,4,0,0
7 520073737070 8,3,1,1,0,0
8 770077007700 0,0,0,0,0,5
9 555555555514 2,0,0,0,2,2
10 764252427600 4,0,4,0,2,0
11 774555554177 3,3,1,3,0,0
12 674574754557 11,5,0,1,0,0
13 000000000000 0,0,0,0,0,0
14 777777777777 0,0,0,0,0,0
15 774377777577 6,0,2,0,0,0
16 070777777777 0,1,1,0,0,0
17 373737373737 0,0,0,0,0,1
18 603260327725 30,0,0,0,0,0
19 466331144663 30,0,0,0,0,0
20 000000000242 3,2,0,0,0,0
21 567656043772 18,2,1,0,0,0
22 200763012420 15,4,1,0,0,0
23 400101140052 14,3,0,0,0,0
24 764767476476 13,2,0,1,0,0
25 001110140110 12,2,1,0,0,0
26 765405076527 16,3,0,1,0,0
27 377323370373 8,4,2,0,0,0
28 250541131216 11,5,2,0,0,0
29 744165741476 12,3,2,0,0,0
30 042101000300 10,3,0,0,0,0
31 002004554101 11,3,1,0,0,0
32 371707762706 15,1,1,0,0,0
33 130371310175 7,3,1,2,0,0
34 212537003613 13,2,1,1,1,0
35 157700063411 15,3,0,0,0,1
36 011500036007 6,7,1,0,0,0
37 743113313517 17,2,1,0,0,0
38 174105270405 13,3,1,1,0,0
39 427272200311 13,3,2,0,0,0
40 725370332237 12,5,1,1,0,0
41 005640420046 12,1,3,0,0,0
42 700350001101 14,3,1,0,0,0
43 577627744076 16,1,1,1,0,0
44 620332232007 10,4,2,1,0,0
45 260406401000 15,1,1,0,0,0
46 737272723276 5,0,0,0,3,0
47 000400040444 7,0,2,0,0,0
48 370222002177 13,2,2,0,0,0
49 372236024656 9,3,2,0,1,0
50 276131137003 11,6,2,0,0,0
51 742134007240 13,4,2,0,0,0
52 777721775571 13,1,2,0,0,0
53 700301232233 11,2,3,0,0,0"
function solve(sq)
hl,vl=0,0
ans=zeros(Int8,6)
for i in 1:5
for j in 1:7
if sq[i,j] != sq[i+1,j]
hl=hl+1
elseif hl>0
ans[hl]=ans[hl]+1
hl=0
end
if sq[j,i] != sq[j,i+1]
vl=vl+1
elseif vl>0
ans[vl]=ans[vl]+1
vl=0
end
end
end
return ans
end
function main()
str1=split(str,"\n")
for s in str1
sq=fill('0',7,7)
s1=split(s," ")
s1[2]=strip(s1[2])
for (i,m) in enumerate(s1[2])
sn=string(parse(Int,m),base=2)
for j in 1:length(sn)
sq[div(i+1,2),3*(1-mod(i,2))-j+4]=reverse(sn)[j]
end
end
res=solve(sq)
ans=join(res,",")
if ans==strip(s1[3])
sel="pass"
else
sel="fail"
end
print(sel," ",ans,"\n")
end
end
@time main()
Prolog
Juliaから移しました。
tenton/4で10進数からn進数のリストに変換されますので、数字を比較します。
solve1/2で入力値を二つずつまとめて二進数にし一つのリストにして最後に0を加え、
同じことを6回行って、リスト6個のリストを作っています。
最後にsolve/2に戻って7つの0からなるリストを加えています。
solve2/2で比較する二つの列を決めています。
solve3/4で実際に比較しています。nth0でインデックスを0から使えますので、
隣の数字の値が同じ時には、nth0(N1,R1,X,R2),X1 is X+1,nth0(N1,R,X1,R2)で、
ansに相当するリストR1のN1番目の値を1増やしてRとします。N1は現在の長さの変数です。
最初縦方向の長さを調べ、更にtrans/2でリストの行列を転置して、横方向の長さを調べます。
solveのRのヘッドを除いて文字列に直したものが答えです。
%swi-Prolog version 7.4.2
%start.
%:-initialization(start). % ideone
tenton(0,_,L,R):-
length(L,N),N1 is 3-N,length(L1,N1),maplist(=(0),L1),append(L1,L,R),!.
tenton(X,B,L,RL):-
X1 is X div B,R1 is X rem B,tenton(X1,B,[R1|L],RL).
tenton1(S,R):-atom_number(S,X),tenton(X,2,[],R).
add(X,L,R):-R=[X|L].
trans([H],R):-length(H,N),length(L,N),maplist(=([]),L),maplist(add,H,L,R).
trans([H|T],R):-trans(T,R1),maplist(add,H,R1,R).
solve3([[],[]],_,R,R).
solve3([[H1|T1],[H2|T2]],N1,R1,FR):-
(H1=:=H2->(nth0(N1,R1,X,R2),X1 is X+1,nth0(N1,R,X1,R2),N=0);(N is N1+1,R=R1)),
solve3([T1,T2],N,R,FR).
solve2([_,_],[0,0,0,0,0,0,0]).
solve2([H1,H2|T],R):-
solve2([H2|T],R1),solve3([H1,H2],0,[0,0,0,0,0,0,0],R2),maplist(plus,R1,R2,R).
solve1([],[]).
solve1([H1,H2|T],R):-
solve1(T,R1),maplist(tenton1,[H1,H2],L),flatten(L,L1),
append(L1,[0],L2),append([L2],R1,R).
solve(L,R):-
solve1(L,L1),append(L1,[[0,0,0,0,0,0,0]],L2),solve2(L2,R1),
trans(L2,L3),solve2(L3,R2),maplist(plus,R1,R2,R).
start:-str(S),split_string(S,"\n","",L),pre(L),!.
pre([]).
pre([H|T]):-
split_string(H,"\s","\s",[_,B,C]),atom_chars(B,L),solve(L,R),disp(R,C),pre(T).
disp(R,C):-
R=[_|T],atomics_to_string(T,",",S),(S==C->Str=" pass";Str=" fail"),
write(Str),write(" "),writeln(S->C).
str("0 060276724276 6,2,1,1,0,1
1 770175454177 2,3,0,3,1,0
2 743733377170 9,3,1,0,0,0
3 724212121273 5,2,1,1,1,1
4 100000000000 3,0,0,0,0,0
5 000002000000 4,0,0,0,0,0
6 003622223600 0,4,0,4,0,0
7 520073737070 8,3,1,1,0,0
8 770077007700 0,0,0,0,0,5
9 555555555514 2,0,0,0,2,2
10 764252427600 4,0,4,0,2,0
11 774555554177 3,3,1,3,0,0
12 674574754557 11,5,0,1,0,0
13 000000000000 0,0,0,0,0,0
14 777777777777 0,0,0,0,0,0
15 774377777577 6,0,2,0,0,0
16 070777777777 0,1,1,0,0,0
17 373737373737 0,0,0,0,0,1
18 603260327725 30,0,0,0,0,0
19 466331144663 30,0,0,0,0,0
20 000000000242 3,2,0,0,0,0
21 567656043772 18,2,1,0,0,0
22 200763012420 15,4,1,0,0,0
23 400101140052 14,3,0,0,0,0
24 764767476476 13,2,0,1,0,0
25 001110140110 12,2,1,0,0,0
26 765405076527 16,3,0,1,0,0
27 377323370373 8,4,2,0,0,0
28 250541131216 11,5,2,0,0,0
29 744165741476 12,3,2,0,0,0
30 042101000300 10,3,0,0,0,0
31 002004554101 11,3,1,0,0,0
32 371707762706 15,1,1,0,0,0
33 130371310175 7,3,1,2,0,0
34 212537003613 13,2,1,1,1,0
35 157700063411 15,3,0,0,0,1
36 011500036007 6,7,1,0,0,0
37 743113313517 17,2,1,0,0,0
38 174105270405 13,3,1,1,0,0
39 427272200311 13,3,2,0,0,0
40 725370332237 12,5,1,1,0,0
41 005640420046 12,1,3,0,0,0
42 700350001101 14,3,1,0,0,0
43 577627744076 16,1,1,1,0,0
44 620332232007 10,4,2,1,0,0
45 260406401000 15,1,1,0,0,0
46 737272723276 5,0,0,0,3,0
47 000400040444 7,0,2,0,0,0
48 370222002177 13,2,2,0,0,0
49 372236024656 9,3,2,0,1,0
50 276131137003 11,6,2,0,0,0
51 742134007240 13,4,2,0,0,0
52 777721775571 13,1,2,0,0,0
53 700301232233 11,2,3,0,0,0").
CodeIQ:境界の長さ
問題とサンプルはこちらのお世話になりました。
https://sw-logic.com/Portfolio/Programing/CodeIQ/3133.php
Juliaで解きました。
隣の升を比較するところが同じな類題です。
16進数を10進数に変換しさらに2進数の文字列に変換しています。
条件別に加算をしていくだけですので、二次元の配列は作らずに、
文字列をつないで計算で位置を求めてみました。
文字列を作るときに桁数が足りないところは'0'を追加しました。
テストケースがサンプルしかありませんが、複雑な問題ではありませんので、
多分大丈夫だと思います。
# Julia v 1.0,1.4
inp=[["f7","8f","44","7a","e6","8f","20","af"],["ff","bc","94","fc","89","a3","45","23"]]
out=[[16,17,11,12],[10,15,12,13]]
function solve(x)
gr,re,ye,bl=0,0,0,0
for i in 1:7,j in 1:8
if x[j+(i-1)*8] != x[j+i*8]
if x[j+(i-1)*8]=='1'
gr+=1
else
re+=1
end
end
if x[i+(j-1)*8] != x[i+1+(j-1)*8]
if x[i+(j-1)*8]=='1'
ye+=1
else
bl+=1
end
end
end
return [re,gr,bl,ye]
end
function main()
for i in 1:2
x=""
for j in 1:8
y=string(parse(Int32, inp[i][j],base= 16),base=2)
n=8-length(y)
y="0"^n*y
x=x*y
end
res=solve(x)
if res==out[i]
sel="pass"
else
sel="fail"
end
print(sel," ",res,"\n")
end
end
@time main()