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

Popular posts from this blog

12 วิธี การบริการและดูแลลูกค้าในร้าน Starbucks

[Android Dev] การติดตั้ง Eclipse+AndroidSDK เพื่อพัฒนาโปรแกรมบน Android

5 TED Talk ที่จะช่วยให้คุณทำงานดีขึ้น