Google Code Jam 2013 รอบคัดเลือก
ปีนี้สุดท้ายแล้วได้มา 80 คะแนนครับ อันดับอยู่ 8 พันกว่าๆ เนื่องจาก กว่าจะตื่นมาทำก็เที่ยงละ แล้วข้อสุดท้ายที่ทำได้ ก็เล่นเอาเกือบหมดเวลา (ตี 4 ของอีกวัน หมดเวลา 7 โมงเช้า)
ทรมานคนแข่งประเทศอื่น Google ก็คิดว่า Programmer ต้องนอนดึกเลยจัดแข่ง 11.00PM เวลาที่นู่น
ซึ่งเมืองไทยก็ 6 โมงไงครับ Programmer ที่นี่ บางทีพึ่งจะนอนหลับกัน (รึปล่าว ?)
ผมทำไปทั้งหมด 3 ข้อ
Problem A. Tic-Tac-Toe-Tomek
อันนี้ไม่มีอะไรครับ เป็น OX แบบ 4x4 ที่มีตัวพิเศษคือ T อยู่บนตาราง 1 ตัว (หรืออาจจะไม่มี) ซึ่ง T จะเป็นตัวพิเศษคือถ้ามี O หรือ X จำนวน 3 ตัวแล้วมี T ไม่ว่าจะแทรกอยู่หรือต่อท้าย เป็นว่าชนะ
Input ตารางเข้าไปแล้วให้หาว่า ใครชนะ เสมอ หรือเกมส์ยังไม่จบ
ตอนแรกคิดว่า T จะต้องต่อ XXX เท่านั้น แต่มาอ่านอีกที T เนี่ยแทรกอยู่ตรงไหนก็ได้
Algorithm ที่ผมใช้ เลยใช้ประโยชน์จากตัวภาษา แล้วนับจำนวนเลย
(ตอนแรกก็เขียน check แถวหลักธรรมดาแหละ แต่ Code ยาวไปยันเกือบ 120 บรรทัดมั้ง = =')
test = gets.chomp.to_i
def win_checker(symbol_list, symbol)
symbol_list.count(symbol) == 4 or
(symbol_list.count(symbol) == 3 and symbol_list.count('T') == 1)
end
test = gets.chomp.to_i
test.times do |t|
table = []
n = 3
4.times { table << gets.chomp }
dummy = gets.chomp
x_win = o_win = false
# vertical
vertical_1, vertical_2, vertical_3, vertical_4 = [], [], [], []
0.upto(3) do |i|
vertical_1 << table[i][0]
vertical_2 << table[i][1]
vertical_3 << table[i][2]
vertical_4 << table[i][3]
end
if win_checker(vertical_1, 'X') or
win_checker(vertical_2, 'X') or
win_checker(vertical_3, 'X') or
win_checker(vertical_4, 'X')
x_win = true
elsif win_checker(vertical_1, 'O') or
win_checker(vertical_2, 'O') or
win_checker(vertical_3, 'O') or
win_checker(vertical_4, 'O')
o_win = true
end
# horizontal
horizontal_1, horizontal_2, horizontal_3, horizontal_4 = [], [], [], []
0.upto(3) do |i|
horizontal_1 << table[0][i]
horizontal_2 << table[1][i]
horizontal_3 << table[2][i]
horizontal_4 << table[3][i]
end
if win_checker(horizontal_1, 'X') or
win_checker(horizontal_2, 'X') or
win_checker(horizontal_3, 'X') or
win_checker(horizontal_4, 'X')
x_win = true
elsif win_checker(horizontal_1, 'O') or
win_checker(horizontal_2, 'O') or
win_checker(horizontal_3, 'O') or
win_checker(horizontal_4, 'O')
o_win = true
end
# diagonal
diagonal_right = []
diagonal_left = []
0.upto(3) do |i|
0.upto(3) do |j|
if i == j
diagonal_right << table[i][j]
elsif j == (n - i)
diagonal_left << table[i][j]
end
end
end
if win_checker(diagonal_right, 'X') or
win_checker(diagonal_left, 'X')
x_win = true
elsif win_checker(diagonal_right, 'O') or
win_checker(diagonal_left, 'O')
o_win = true
end
print "Case ##{t + 1}: "
table_string = table.join
if x_win
print "X won\n"
elsif o_win
print "O won\n"
elsif !x_win and !o_win
print (table_string.count('.') != 0) ? "Game has not completed\n" : "Draw\n"
end
end
Problem B. Lawnmower
ข้อนี้ก็โจทย์ไถหญ้าครับ คือมีผัวเมียคู่หนึ่ง ไถหญ้าหน้าบ้านเป็น Pattern ทุกปี (ว่างสินะ) แต่พอดีว่ามีนวัตกรรมเครื่องไถหญ้าใหม่ออกขาย ... คือมันไถตรงไปข้างหน้าได้อย่างเดียว เลือกสักแถวแหละ มันไถเกรียนเท่ากันหมด (ทั้งในแนวแกน X, Y) ให้หาว่า ถ้าให้ Pattern แบบนี้มา จะไถได้หรือไม่ ? ข้อนี้เปลี่ยนมาใช้ Python เขียน ไม่รู้นึกอะไร เปลี่ยนบรรยากาศบ้าง :)
ข้อนี้แหละที่มา Submit ตอนก่อนหมดเวลา
import re
def check_game(lawn):
row_maxes = [max(x) for x in lawn]
cols = [[lawn[i][j] for i in range(len(lawn))] for j in range(len(lawn[0]))]
col_maxes = [max(x) for x in cols]
for i in range(len(lawn)):
for j in range(len(lawn[i])):
val = lawn[i][j]
if val != row_maxes[i] and val != col_maxes[j]:
return "NO"
return "YES"
def read_input():
dims = map(int, raw_input().split())
x,y = int(dims[1]), int(dims[0])
lawn = []
for i in range(y):
line = raw_input()
nums = [int(x.strip()) for x in re.split(" ",line)]
lawn.append(nums)
return lawn
if __name__ == "__main__":
test = input()
for i in xrange(test):
lawn = read_input()
result = check_game(lawn)
print "Case #%d: %s" % (i + 1, result)
Problem C. Fair and Square
โจทย์ข้อนี้คือเมื่อให้ช่วงตัวเลข A - B มา ให้หาว่ามีเลขที่เป็น Palindrome และรากที่สองของตัวเลขนั้นยังคงเป็น Palindrome ด้วย ทั้งหมดกี่ตัว
โจทย์ข้อนี้ผมรันไม่ทันครับ ... ใน small problem มันกระจอกมาก ... Algorithm ที่ใช้เลยรันได้สบายๆ
แต่พอ Large นี่เดี้ยงทันที ... ให้ดูอันที่กากก่อนนะ :P
class Fixnum
def is_palindrome
self.to_s == self.to_s.reverse
end
end
test = gets.chomp.to_i
test.times do |t|
count = 0
a, b = gets.chomp.split.map! { |e| e.to_i }
(a).upto(b) do |i|
if i.to_s.is_palindrome
squared = Math.sqrt(i)
if squared.to_s[squared.to_i.to_s.length + 1, 2] == "0" and
squared.to_s[0, squared.to_i.to_s.length].is_palindrome
count += 1
end
end
end
puts "Case ##{t + 1}: #{count}"
end
จากนั้นก็ได้ไปอ่าน Code ของหลายๆ คนที่ทำได้ครับ (@champjss, @neizod, @jittat) เลยกระจ่างว่าทำยังไง โดยมีอยู่ 2 วิธี ที่น่าสนใจและเข้าใจง่ายคงเป็นวิธี Dynamic Programming ของ @jittat ซึ่งผมแปลงมาเป็น Ruby ได้แบบนี้ครับ (อาจารย์ท่านเขียนด้วย C++)
class Fixnum
def is_palindrome
self.to_s == self.to_s.reverse
end
def square
self * self
end
def between(a, b)
a <= self and self <= b
end
end
palindrome_list = []
def generate_palindrome_list
1.upto(20000000) do |i|
if i.is_palindrome
squared_i = i.square
if squared_i.is_palindrome
palindrome_list << squared_i
end
end
end
end
generate_palindrome_list
test = gets.chomp.to_i
test.times do |t|
a, b = gets.chomp.split.map { |e| e.to_i }
result_count = 0
palindrome_list.each do |each|
if each.between(a, b)
result_count += 1
end
end
puts "Case ##{t + 1}: #{result_count}"
end

Comments
Post a Comment