import random from pathlib import Path import time import os import math LOCAL = False in_path = "./test" out_path = "./test/result" INF=10**20 alpha = 5 FILE_OUTPUT = True def read_data(file): if LOCAL: with open(file,mode="r") as f: data = f.readlines() N,M = map(int,data[0].split()) pos = [[int(x) for x in data[i+1].split()] for i in range(N)] else: N,M=map(int,input().split()) pos = [[int(x) for x in input().split()] for i in range(N)] return N,M,pos #2点間の距離を返す def dist(p1,p2,a=alpha**2): return ((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2) * a # 一番近い惑星を貪欲に選び続ける(Nearest Neighbour法) def nearest_neighbor(pos,N): best_route = [] best_cost = INF for _ in range(10): cost = 0 start_point = random.randint(0,N-1) #初期位置はランダム v = start_point visited = [False] * N visited[v] = True route = [v] # 初期惑星以外のN-1個の惑星を訪問していく for _ in range(N - 1): nearest_dist = INF nearest_v = -1 # 一番近い惑星を探す for next in range(N): if visited[next]: continue d = dist(pos[v], pos[next]) if d < nearest_dist: nearest_dist = d nearest_v = next # 次の頂点に移動 v = nearest_v visited[v] = True route.append(nearest_v) cost += nearest_dist cost += dist(pos[next],pos[start_point]) if cost 10: return False return math.exp(-score/temp) > random.random() #2-opt近傍 def two_opt(state,temp): #print("two-opt") if random.random()<0.4: i = random.randint(1,state.N-2) j = random.randint(1,state.N-2) else: i = random.randint(1,state.N-2) j = (i + random.randint(2,10))%(state.N-1) if i>j: i,j=j,i #(a,b)-(c,d)->(a,c)-(b-d) a = state.route[i] b = state.route[i+1] c = state.route[j] d = state.route[j+1] if len(set({a,b,c,d}))!=4: return False ab_cd = state.calc_distance(a,b) + state.calc_distance(c,d) ac_bd = state.calc_distance(a,c) + state.calc_distance(b,d) if simulated_annealing(ac_bd-ab_cd,temp): state.route[i+1:j+1] = state.route[i+1:j+1][::-1] state.cost += ac_bd-ab_cd return True else: return False #挿入近傍 def point_insert(state,temp): #print("Point_insert") i = random.randint(1,state.N-2) j = random.randint(1,state.N-2) if i>j: i,j=j,i #(a,b,c)-(d,e)->(a,c)-(d,b,e) a = state.route[i-1] b = state.route[i] c = state.route[i+1] d = state.route[j] e = state.route[j+1] if len(set({a,b,c,d,e}))!=5: return False abc_de = state.calc_distance(a,b) + state.calc_distance(b,c) + state.calc_distance(d,e) ac_dbe = state.calc_distance(a,c) + state.calc_distance(d,b) + state.calc_distance(b,e) if simulated_annealing(ac_dbe-abc_de,temp): state.route.remove(b) if i>2)&1: B,C=C,B if (mode>>1)&1: D,E=E,D if mode&1: F,A=A,F new_cost = state.calc_distance(A,B) + state.calc_distance(C,D) + state.calc_distance(E,F) cost_list.append((new_cost-current_cost,mode)) cost_list.sort() if cost_list[0][1]!=0: next_mode = cost_list[0][1] state.cost += cost_list[0][0] elif simulated_annealing(cost_list[1][0],temp): next_mode = cost_list[1][1] state.cost += cost_list[1][0] else: return False if (i - 1) < (k % len(state.route)): first_segment = state.route[k% len(state.route):] + state.route[:i] else: first_segment = state.route[k % len(state.route):i] second_segment = state.route[i:j] third_segment = state.route[j:k] if next_mode&1: first_segment.reverse() if (next_mode>>1)&1: third_segment.reverse() if (next_mode>>2)&1: second_segment.reverse() state.route = first_segment + second_segment + third_segment return True #宇宙船の位置を少し動かす def move_station(state,temp): move_range = 30 m = random.randint(0,state.M-1) x,y = state.center_pos[m] dx = random.randint(-move_range,move_range) dy = random.randint(-move_range,move_range) current_cost = state.cost x_new = max(0,min(1000,x+dx)) y_new = max(0,min(1000,y+dy)) state.center_pos[m] = [x_new,y_new] new_cost = state.calc_cost() if simulated_annealing(new_cost-current_cost,temp): return True else: state.center_pos[m]=[x,y] #宇宙ステーションを別の場所に移動させる def replace_station(state,temp): point_ls = list(find_edge_point(state,2)) ini_x = (state.pos[point_ls[0]][0]+state.pos[point_ls[1]][0])//2 ini_y = (state.pos[point_ls[0]][1]+state.pos[point_ls[1]][1])//2 ini_point = [ini_x,ini_y] surrounding = [] for p in range(state.N): if dist(ini_point,state.pos[p],a=1)<=100: surrounding.append(p) if not surrounding: return False new_pos = [sum(state.pos[p][s] for p in surrounding)//len(surrounding) for s in range(2)] current_cost = state.calc_cost() m = random.randint(0,state.M-1) prev_pos = state.center_pos[m] state.center_pos[m]= new_pos state.find_nearest_station() new_cost = state.calc_cost() if simulated_annealing(new_cost-current_cost,temp): return True else: state.center_pos[m]=prev_pos state.find_nearest_station() new_cost = state.calc_cost() return False def adjust_station(state,temp): path = state.ans() L=len(path) M=state.M edge_count = [0]*M edge_x_sum = [0]*M edge_y_sum = [0]*M for i in range(L-1): if path[i]<0 and path[i+1]>=0: p,q = -path[i]-1,path[i+1] edge_count[p]+=5 edge_x_sum[p]+=pos[q][0]*5 edge_y_sum[p]+=pos[q][1]*5 elif path[i]>=0 and path[i+1]<0: p,q = -path[i+1]-1,path[i] edge_count[p]+=5 edge_x_sum[p]+=pos[q][0]*5 edge_y_sum[p]+=pos[q][1]*5 elif path[i]<0 and path[i+1]<0: p,q = -path[i]-1,-path[i+1]-1 edge_count[p]+=1 edge_count[q]+=1 edge_x_sum[p]+=pos[q][0] edge_y_sum[p]+=pos[q][1] edge_x_sum[q]+=pos[p][0] edge_y_sum[q]+=pos[p][1] for m in range(M): if edge_count[m]==0: state.center_pos[m] = [random.randint(0,1000),random.randint(0,1000)] else: state.center_pos[m] = [edge_x_sum[m]//edge_count[m],edge_y_sum[m]//edge_count[m]] state.cost = state.calc_cost() return True #焼きなましで経路を短くする def optimize_route(state,mode_ls,time_limit,start_temp,end_temp): dt=time.time() trial = dict() success = dict() for mode in mode_ls: trial[mode[0]]=0 success[mode[0]]=0 while time.time()-dt= limit: return point_ls def K_means_clustering(state): best_pos = [] best_cost = INF for _ in range(4): num = random.randint(25,35) use_list = find_edge_point(state,num) valid_station = {0,1,2,3} for m in range(state.M): if not m in valid_station: state.center_pos[m]=[INF,INF] for _ in range(15): state.find_nearest_station() state.set_station(use_list,valid_station) num = random.randint(25,35) use_list = find_edge_point(state,num) valid_station = {4,5,6,7} for _ in range(15): state.find_nearest_station() state.set_station(use_list,valid_station) cost = state.calc_cost() if costbest_score: best_score = score best_pos = center_pos best_ans = ans output(best_pos,best_ans,score)