Sony GO FOR IT 5) 申告制エレベータ

i)

# coding: utf-8
# ライセンス:このプログラムは好きに使ってください

import sys

# 利用者
class user:
    def __init__(self,id_,t_,s_,g_):
        self.id,self.t,self.s,self.g = id_,t_,s_,g_
    def __repr__(self):
        return "user(%d,%d,%d,%d)"%(self.id,self.t,self.s,self.g)

# 入力
U = [user(*map(int,l[:-1].split(","))) for l in sys.stdin]

es = 1      # エレベータのある階
et = 0      # 直前の動作の時刻
ed = "E"    # 扉の状態
eu = []     # 乗員
up = 0      # user[up]を次に運ぶ

while up<len(U):
    u = []  # 乗り降りする利用者
    if ed=="E":
        # 扉が閉じているなら開ける
        ed = "B"
        if eu==[]:
            # 乗員がいなければ次の利用者のいる階
            s = U[up].s
        else:
            # 乗員がいるなら乗員の目的階で扉を開ける
            s = U[eu[0]].g
            u = [U[eu[0]].id]
            eu = []
            up += 1
        et += abs(s-es)*2
        es = s
    else:
        # 扉が開いているなら閉じる
        ed = "E"
        if U[up].s==es:
            # 待っている利用者がいる
            u = [U[up].id]
            eu = [up]
            et = max(et+5,U[up].t)
        else:
            # 待っている利用者がいない
            et += 5
    u += [0]*(5-len(u))
    print "1,%s,%s,%s,%s,%s,%s,%s,%s"%(et,es,ed,u[0],u[1],u[2],u[3],u[4])

ii)

JavaScriptでエレベータの動きを可視化した。

http://sanya.sweetduet.info/goforit/5_2.html

iii)

(A*ではなく)ダイクストラ法。input_i.csvは解けるけど、input_iii_iv.csvは解けないorz

# ライセンス:このプログラムは好きに使ってください。
# coding: utf-8

import sys
import copy
import heapq

# 利用者
class user:
    def __init__(self,i,t,s,g):
        self.id,self.time,self.start,self.goal = i,t,s,g
    def __repr__(self):
        return "user(%d,%d,%d,%d)"%(self.id,self.time,self.start,self.goal)

# 入力
U = [user(*map(int,l[:-1].split(","))) for l in sys.stdin]

# 状態
class state:
    def __init__(self):
        self.C = 0          # コスト
        self.H = sum(u.time for u in U) # ヒューリスティック
        self.time = 0       # 時刻
        self.floor = 1      # エレベータのある階
        self.door = "E"     # 扉の状態(E:閉, B:開)
        self.elev = []      # エレベータに乗っている利用者
        self.remain = (1<<len(U))-1 # エレベータに乗る前の利用者
        self.count = len(U) # エレベータに乗る前+エレベータに乗っている利用者数
        self.flag = False   # 扉が開いたときに利用者が降りたかどうか
        self.prev = None    # 直前の状態
        self.edge = ""      # 直前の状態からの遷移方法
    def __lt__(self,other):
        return self.C+self.H < other.C+self.H
    def __repr__(self):
        return "state(%s,%s,%s,%s,%s,%s)"%(self.C,self.time,self.floor,self.door,self.elev,self.count)
    def __copy__(self):
        s = state()
        s.C = self.C
        s.time = self.time
        s.floor = self.floor
        s.door = self.door
        s.elev = self.elev[:]
        s.remain = self.remain
        s.count = self.count
        s.flag = self.flag
        return s

S = [state()]

c = 0
while len(S)>0:
    s = heapq.heappop(S)
    
    if s.count==0:
        goal = s
        break
    c += 1
    if c%1000==0:
        print c,len(S),s
    
    if s.door=="E":
        # 扉が閉じているなら、どこかの階で開く
        for floor in range(1,11):
            # 与えられている入力なら問題無い
            if floor==s.floor:
                continue
            
            t = copy.copy(s)
            time = abs(floor-s.floor)*2 # 所要時間
            t.C += t.count*time
            t.H = 0
            t.time += time
            t.floor = floor
            t.door = "B"
            
            # この階が目的の利用者を降ろす
            u = []
            t.elev = []
            t.flag = False
            for x in s.elev:
                if U[x].goal==floor:
                    u += [x+1]
                    t.count -= 1
                else:
                    t.elev += [x]
            t.flag = u!=[]
            
            t.prev = s
            u += [0]*(5-len(u))
            t.edge = "1,%s,%s,B,%s,%s,%s,%s,%s"%(t.time,floor,u[0],u[1],u[2],u[3],u[4])
            
            heapq.heappush(S,t)
    else:
        # 扉が開いているなら5秒もしくは5秒以上で利用者が来るまで待って閉じる
        for time in [5]+[u.time-s.time for u in U if u.time>s.time+5 and u.start==s.floor]:
            t = copy.copy(s)
            t.C += t.count*time
            t.H = 0
            t.time += time
            t.door = "E"
            
            # 乗車可能な利用者を乗せる
            u = []
            for i,ui in enumerate(U):
                if t.remain>>i&1 and ui.time<=t.time and ui.start==t.floor:
                    t.elev += [i]
                    t.remain ^= 1<<i
                    u += [i+1]
            
            t.prev = s
            u += [0]*(5-len(u))
            t.edge = "1,%s,%s,E,%s,%s,%s,%s,%s"%(t.time,t.floor,u[0],u[1],u[2],u[3],u[4])
            
            if t.flag or u!=[0]*5:
                heapq.heappush(S,t)

hist = []
x = goal
while x.prev:
    hist += [x.edge]
    x = x.prev
for h in hist[::-1]:
    print h
print goal.C - sum(u.time for u in U)