data1 = sampleSub.readlines() sampleSub.close() subData = h.makeTable(data1, 1) lastScore = INFINITE count = -1 lastStageScore = 0 # 01 while True: while True: count += 1 # 02 현재 상태에 대한 score를 계산하여 출력한다. (feasible하지 않으면 무한대) ocA = h.getOccupancy(famData, subData) # occupancy array score = h.getScoreFeasible(famData, subData, ocA) # 지난 단계의 score와 같으면 더 이상 업데이트가 되지 않으므로 랜덤하게 5개 변경 (미구현) converged = False if lastStageScore == score: converged = True # 지난 단계(while문 loop)의 score를 업데이트 lastStageScore = score # 03 For 모든 families for i in range(FAMILIES): if (count == 0 and i % 50 == 0) or (count > 0 and i % 200 == 0): print( str(count) + ' ' + str(i) + ' / score: ' + str(score) + ' / checksum: ' + str(sum(ocA)) + ' ' + str(max(ocA)) +
def findBestOption(subData, famData, options, ocA, ci, i, prevScore): # condition = (ci == 17 and i >= 0 and i < 5) condition = False # 04 각 option에 따른 score의 변화량을 저장한 배열을 초기화한다. scoreChange = [] for j in range(len(options)): scoreChange.append(None) befores = [ ] # value of 'before' for each option: [opt0:[o0b0, o0b1], opt1:[o1b0, o1b1, o1b2, o1b3], ...] afters = [ ] # value of 'after' for each option: [opt0:[o0a0, o0a1], opt1:[o1a0, o1a1, o1a2, o1a3], ...] isFeasible = [] # 05 For 모든 options (0, 1, 2, ..., and 9) for j in range(len(options)): if condition == True: print('\n' + str(j)) thisOption = options[ j] # 변경사항: [[famK0, optK0], [famK1, optK1], ..., [famKA, optKA]] if condition == True: print('[**] thisOption = ' + str(thisOption)) # 06 ocA 및 subData를 복사한 배열을 만든다. ocA_copy = [] for k in range(len(ocA)): ocA_copy.append(ocA[k]) if len(thisOption) >= 2: subData_copy = [] for k in range(len(subData)): subData_copy.append([subData[k][0], subData[k][1]]) before_ = [ ] # 'before' values of option j : for example [o0b0, o0b1, o0b2] after_ = [ ] # 'after' values of option j : for example [o0a0, o0a1, o0a2] isFeasible = True # ocA >= 125 and ocA <= 300 scoreChangeSum = 0 # sum of score change # 각 option에 대하여 (famK0, famK1, ..., famKA에 대하여 변경) # 처음의 p0, A0, B0 값과 마지막 p1, A1, B1 값만을 이용 (단일 변경의 경우 처음과 마지막이 같으므로 모두 이용) for k in range(len(thisOption)): if condition == True: print('[00] k = ' + str(k)) famID = thisOption[k][0] # option의 변경사항 k에 대한 family ID toChange = thisOption[k][ 1] # option의 변경사항 k에 대한 change to this option (0, 1, ..., or 9) if condition == True: print('[01] famID: ' + str(famID) + ', toChange: ' + str(toChange)) if len(thisOption) >= 2: before = subData_copy[famID][1] # 변경 전 date (option) else: before = subData[famID][1] # 변경 전 date (option) if toChange < 10: after = famData[famID][toChange + 1] # 변경 후 date (option) else: after = toChange - 100 # 변경 후 date (option) - toChange가 10 이상(101~200)이면 100을 뺀 값으로 지정 if condition == True: print('[02] before: ' + str(before) + ', after: ' + str(after)) before_.append(before) after_.append(after) if condition == True: print('[03] before_: ' + str(before_) + ', after_: ' + str(after_)) members = famData[famID][11] # 07 p0 = 해당 family에 대한 prefCost를 계산한다. # p0 : 해당 family에 대한 date 변경 전 prefCost p0 = prefCostForThisFamily(famData[famID], [famID, before]) if condition == True: print('[04] p0: ' + str(p0) + ' / famID=' + str(famID) + ', famData[famID]=' + str(famData[famID]) + ', before=' + str(before)) # before와 after가 서로 같으면 변화가 없는 것이므로 건너뛰기 if before == after: continue # 08 B0 = 변경전 day가 before일 때 day (before-5) ~ day (before+5) 부분을 추출하여 account penalty를 계산한다. # B0 : 변경 전 date의 ocA 변경 전 account penalty beforeOCA = [None] * max(6 - before, 0) + ocA_copy[max( before - 5, 1):min(before + 6, 101)] + [ocA_copy[100]] * max( 0, before - 95) if before == 100: B0 = accountPenaltyFor100(beforeOCA) else: B0 = accountPenalty(beforeOCA) if condition == True: print('[05] B0: ' + str(B0) + ' / beforeOCA=' + str(beforeOCA)) # 09 A0 = 변경후 day가 after일 때 day (after-5) ~ day (after+5) 부분을 추출하여 account penalty를 계산한다. # A0 : 변경 후 date의 ocA 변경 전 account penalty afterOCA = [None] * max(6 - after, 0) + ocA_copy[ max(after - 5, 1):min(after + 6, 101)] + [ocA_copy[100]] * max( 0, after - 95) if after == 100: A0 = accountPenaltyFor100(afterOCA) else: A0 = accountPenalty(afterOCA) if condition == True: print('[06] A0: ' + str(A0) + ' / afterOCA=' + str(afterOCA)) # 10 [IMPORTANT] ocA 배열 갱신: ocA_copy[before] -= people; ocA_copy[after] += people; if condition == True: print( str(before) + '->' + str(after) + ' ( members: ' + str(members) + ' ) :' + ' ocA_copy[' + str(before) + '] = ' + str(ocA_copy[before]) + ', ocA_copy[' + str(after) + '] = ' + str(ocA_copy[after])) for x in range(len(ocA_copy)): if x == before and x != after: ocA_copy[x] -= members elif x != before and x == after: ocA_copy[x] += members else: continue if condition == True: print( str(before) + '->' + str(after) + ' ( members: ' + str(members) + ' ) :' + ' ocA_copy[' + str(before) + '] = ' + str(ocA_copy[before]) + ', ocA_copy[' + str(after) + '] = ' + str(ocA_copy[after])) # 11 B1 = 변경전 day가 before일 때 day (before-5) ~ day (before+5) 부분을 추출하여 account penalty를 계산한다. # B1 : 변경 전 date의 ocA 변경 후 account penalty beforeOCA_copy = [None] * max(6 - before, 0) + ocA_copy[max( before - 5, 1):min(before + 6, 101)] + [ocA_copy[100]] * max( 0, before - 95) if before == 100: B1 = accountPenaltyFor100(beforeOCA_copy) else: B1 = accountPenalty(beforeOCA_copy) if condition == True: print('[10] B1: ' + str(B1) + ' / beforeOCA_copy=' + str(beforeOCA_copy)) # 12 A1 = 변경후 day가 after일 때 day (after-5) ~ day (after+5) 부분을 추출하여 account penalty를 계산한다. # A1 : 변경 후 date의 ocA 변경 후 account penalty afterOCA_copy = [None] * max(6 - after, 0) + ocA_copy[ max(after - 5, 1):min(after + 6, 101)] + [ocA_copy[100]] * max( 0, after - 95) if after == 100: A1 = accountPenaltyFor100(afterOCA_copy) else: A1 = accountPenalty(afterOCA_copy) if condition == True: print('[11] A1: ' + str(A1) + ' / afterOCA_copy=' + str(afterOCA_copy)) # 15 p1 = 해당 family에 대한 변경된 prefCost를 계산한다. # p1 : 해당 family에 대한 date 변경 후 prefCost p1 = prefCostForThisFamily(famData[famID], [famID, after]) if condition == True: print('[12] p1: ' + str(p1) + ' / famID=' + str(famID) + ', famData[famID]=' + str(famData[famID]) + ', after=' + str(after)) # 16 해당 option에 대한 account penalty의 변화량 [(A1s+B1s)-(A0s+B0s)], # prefCost의 변화량 (p1s-p0s)을 이용하여 score의 변화량 (B1s+A1s+p1s)-(B0s+A0s+p0s)을 계산한다. thisScoreChange = (A1 + B1 + p1) - (A0 + B0 + p0) scoreChangeSum += thisScoreChange if condition == True: print('< score change of ' + str(j) + ' > 1[all/aA/aB/p]: ' + str(round(A1 + B1 + p1, 1)) + '\t' + str(round(A1, 1)) + '\t' + str(round(B1, 1)) + '\t' + str(round(p1, 1)) + ',\t0[all/bA/bB/p]: ' + str(round(A0 + B0 + p0, 1)) + '\t' + str(round(A0, 1)) + '\t' + str(round(B0, 1)) + '\t' + str(round(p0, 1)) + ',\tdif: ' + str(round(thisScoreChange, 1))) # change copy of subData if len(thisOption) >= 2: subData_copy[famID] = [subData_copy[famID][0], after] # before_, after_를 각각 befores, afters에 추가 befores.append(before_) afters.append(after_) if condition == True: print('[13] befores: ' + str(befores)) print('[14] afters : ' + str(afters)) # Feasible하지 않으면 (max>300 or min<125) 해당 option 건너뛰기 if max(ocA_copy) > 300 or min(ocA_copy[1:]) < 125: scoreChange[j] = None continue else: scoreChange[j] = scoreChangeSum if condition == True: print('[15] scoreChange: ' + str(scoreChange)) # scoreChange가 모두 None이면 건너뛰기 allNone = [] for j in range(len(options)): allNone.append(None) if scoreChange == allNone: return prevScore # if ci == 17: print('min score = ' + str(minNone(scoreChange)[0])) # 17 기존 option에 대한 score보다 낮은 score인 option이 있으면 (즉 score의 변화량 < 0) if minNone(scoreChange)[0] < 0: if condition == True: roundPrint(scoreChange, 3) # 18 score(의 변화량)가 가장 작은 (음수 중에서는 절댓값이 가장 큰) option을 찾아서 실행한다. minBefore = [] # 가장 작은 option의 before 값들의 집합 minAfter = [] # 가장 작은 option의 after 값들의 집합 minFamIDs = [] # 가장 작은 option의 family ID의 집합 minChoiceSC = 0 # 가장 작은 option의 score의 변화량 minChoices = [] # 가장 작은 option의 option 번호(0~9)의 집합 minK = -1 # 가장 작은 option에 대한 k 값 for k in range(len(scoreChange)): if scoreChange[k] == None: continue if scoreChange[k] < minChoiceSC: minChoiceSC = scoreChange[k] minK = k # 해당 option의 family ID 및 option 번호 추출 thisOption = options[k] minBefore = [] # in the form of [oKb0, oKb1, ...] minAfter = [] # in the form of [oKa0, oKa1, ...] minFamIDs = [] # in the form of [famK0, famK1, ...] minChoices = [] # in the form of [optK0, optK1, ...] # 해당 option에 대한 before 및 after 값 추출 # befores : [opt0:[o0b0, o0b1], opt1:[o1b0, o1b1, o1b2, o1b3], ...] # afters : [opt0:[o0a0, o0a1], opt1:[o1a0, o1a1, o1a2, o1a3], ...] for x in range(len(thisOption)): minFamIDs.append(thisOption[x][0]) minChoices.append(thisOption[x][1]) minBefore.append(befores[k][x]) minAfter.append(afters[k][x]) if condition == True: print('[15] minFamIDs : ' + str(minFamIDs)) print('[16] minChoices : ' + str(minChoices)) print('[17] minBefore : ' + str(minBefore)) print('[18] minAfter : ' + str(minAfter)) # subData 변경 for k in range(len(thisOption)): if minChoices[k] < 10: # 가장 작은 choice의 옵션의 번호가 10 미만이면 subData[minFamIDs[k]][1] = famData[minFamIDs[k]][minChoices[k] + 1] else: # 10 이상이면 100을 뺀 값으로 지정 (즉 101 <= minChoices[k] <= 200) subData[minFamIDs[k]][1] = minChoices[k] - 100 # minFamIDs[k]에 해당하는 members members = famData[minFamIDs[k]][11] if condition == True: print('< minK = ' + str(minK) + ' > minChoices: ' + str(minChoices)) print('[19] minFamIDs[k] : ' + str(minFamIDs[k])) print('[20] subData[minFamIDs[k]][1] : ' + str(subData[minFamIDs[k]][1])) print('[21] minChoices[k] : ' + str(minChoices[k])) print('[22] ocA[minBefore[k]] BEFORE : ' + str(ocA[minBefore[k]])) print('[23] ocA[minAfter[k]] BEFORE : ' + str(ocA[minAfter[k]])) # 19 occupancy array를 업데이트한다. (ocA[before of minChoice] -= people; ocA[after of minChoice] += people;) ocA[minBefore[k]] -= members ocA[minAfter[k]] += members if condition == True: print('[22] minBefore[k] : ' + str(minBefore[k])) print('[23] minAfter[k] : ' + str(minAfter[k])) print('[24] ocA[minBefore[k]] AFTER : ' + str(ocA[minBefore[k]])) print('[25] ocA[minAfter[k]] AFTER : ' + str(ocA[minAfter[k]])) print('[26] k = ' + str(k) + ', members = ' + str(members)) score = h.getScoreFeasible(famData, subData, ocA) if condition == True: print('minChoSC : ' + str(minChoiceSC) + ' -> ' + str(score) + '\n') # temp return score # 가장 작은 변화량이 0 초과이면 변화가 없으므로 이전 값을 반환 return prevScore
# read sample submission data sampleSub = open('sample_submission.csv', 'r') data1 = sampleSub.readlines() sampleSub.close() subData = h.makeTable(data1, 1) lastScore = 2147483647 # initialize each row of submission data as choice_0 for i in range(FAMILIES): subData[i][1] = famData[i][1] ocA = h.getOccupancy(famData, subData) print(h.prefCost(famData, subData, ocA)) print(h.accountPenalty(famData, subData, ocA)) lastScore = h.getScoreFeasible(famData, subData, ocA) print(lastScore) print(ocA) # make feasible print('times 1') options = [] for i in range(len(subData)): options.append(0) while True: ocA = h.getOccupancy(famData, subData) maxVal = -1 minVal = 9999 maxIndex = -1