# -*- coding: UTF-8 -*- import sys from math import * from random import * from datetime import * import numpy as np ########################## # 距離の計算 # n_c : 都市の数 # p : 都市番号 # rg : 都市間の距離 # return : 距離(負) ########################## def kyori(n_c, p, rg) : r = 0 n1 = p[0] for i1 in range(1, n_c) : n2 = p[i1] r -= rg[n1][n2] n1 = n2 n2 = p[0] r -= rg[n1][n2] return r ######################### # クラスIterationの定義 ######################### class Iteration : ############################ # コンストラクタ # name : ファイル名 ############################ def __init__(self, name) : # ファイルのオープン inn = open(name, "r") # 基本データ s = inn.readline().split() self.n_city = int(s[1]) # 都市の数 self.max_try = int(s[3]) # 最大試行回数 self.sel = int(s[5]) # エッジの選択方法 # =0 : 最良のものを選択 # =1 : 最初のものを選択 self.neib = int(s[7]) # 近傍(2 or 3) s = inn.readline().split() self.out_lvl = int(s[1]) # 出力レベル # =0 : 最終出力だけ # n>0 : n回毎に出力(負の時はファイル) self.out_m = int(s[3]) # 出力方法 # =-1 : 出力しない # =0 : すべてを出力 # =1 : 評価値だけを出力(最終結果だけはすべてを出力) s = inn.readline().split() self.o_file = s[1] # 出力ファイル名 self.out_d = int(s[3]) # 表示間隔 # 都市の位置データ self.city = np.empty((self.n_city, 2), np.int) for i1 in range(0, self.n_city) : s = inn.readline().split() self.city[i1][0] = int(s[0]) self.city[i1][1] = int(s[1]) # ファイルのクローズ inn.close() # 距離テーブルの作成 self.rg = np.empty((self.n_city, self.n_city), np.int) # 都市間の距離 for i1 in range(0, self.n_city) : for i2 in range(i1+1, self.n_city) : x = self.city[i2][0] - self.city[i1][0] y = self.city[i2][1] - self.city[i1][1] self.rg[i1][i2] = int(sqrt(x * x + y * y) + 0.5) for i1 in range(0, self.n_city) : for i2 in range(0, i1) : self.rg[i1][i2] = self.rg[i2][i1] # 都市を訪れる順序(初期設定) self.seq = np.empty(self.n_city, np.int) # 都市を訪れる順序 self.seq_w1 = np.empty(self.n_city, np.int) # 都市を訪れる順序(ワーク) self.seq_w2 = np.empty(self.n_city, np.int) # 都市を訪れる順序(ワーク) for i1 in range(0, self.n_city) : sw = 0 while sw == 0 : ct = int(random() * self.n_city) if ct >= self.n_city : ct = self.n_city - 1 self.seq[i1] = ct sw = 1 for i2 in range(0, i1) : if ct == self.seq[i2] : sw = 0 break ################# # 最適化の実行 ################# def Optimize(self) : # 初期設定 n_tri = 0 max = np.empty(1, np.int) max[0] = kyori(self.n_city, self.seq, self.rg) if self.out_m >= 0 and abs(self.out_lvl) > 0 : print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) self.Output(self.out_lvl, n_tri, max[0]) # 実行 sw = 1 for n_tri in range(1, self.max_try+1) : # 改善 sw = self.Change(max) # 出力 if self.out_d > 0 and n_tri%self.out_d == 0 : print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) if self.out_m >= 0 and abs(self.out_lvl) > 0 : if n_tri%abs(self.out_lvl) == 0 : self.Output(self.out_lvl, n_tri, max[0]) if sw <= 0 : break # 最終出力 if self.out_m >= 0 : n_tri -= 1 k1 = self.out_m self.out_m = 0 print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) self.Output(self.out_lvl, n_tri, max[0]) self.out_m = k1 return n_tri ############################### # 出力 # sw : >=0 : 出力先未定 # <0 : ファイル # n_tri : 現在の試行回数 # r : 距離の負値 ############################### def Output(self, sw, n_tri, r) : k = 0 pr = -1 if sw >= 0 : pr = int(input(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ")) if pr != 0 : if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(self.o_file, "a") out.write("***試行回数 " + str(n_tri) + " 距離 " + str(-r) + " 時間 " + now + "\n") if self.out_m == 0 : for i1 in range(0, self.n_city) : n = self.seq[i1] out.write(" " + str(n) + " " + str(self.city[n][0]) + " " + str(self.city[n][1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr <= 0 : out.close() ###################################### # エッジの入れ替え # r_m : 距離の負値 # return : =0 : 改善がなかった # =1 : 改善があった ###################################### def Change(self, r_m) : ch = 0 sw = 0 max = r_m[0] n3 = int(random() * (self.n_city - 2)) if n3 > self.n_city-3 : n3 = self.n_city - 3 # 2近傍 i1 = 0 while i1 <= self.n_city-3 and ch == 0 : n1 = self.n_city - 1 if n3 == 0 : n1 = self.n_city - 2 i2 = n3 + 2 while i2 <= n1 and ch == 0 : # 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 k2 = i2 + 1 if i2 == self.n_city-1 : k2 = 0 # 枝の入れ替え self.seq_w1[0] = self.seq[n3] k = 1 for i3 in range(k1, n3, -1) : self.seq_w1[k] = self.seq[i3] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価 r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 i2 += 1 n3 += 1 if n3 > self.n_city-3 : n3 = 0 i1 += 1 # 3近傍 if self.neib == 3 and ch == 0 : i1 = 0 while i1 <= self.n_city-3 and ch == 0 : n1 = self.n_city - 2 n2 = self.n_city - 1 i2 = n3 + 1 while i2 <= n1 and ch == 0 : i3 = i2 + 1 while i3 <= n2 and ch == 0 : # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 k2 = i3 + 1 if i3 == self.n_city-1 : k2 = 0 # 枝の入れ替えと評価 # 入れ替え(その1) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2, n3, -1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(k1, i2, -1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その1) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その2) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(k1, i2, -1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その2) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その3) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(i2, n3, -1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その3) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その4) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その4) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 i3 += 1 i2 += 1 n3 += 1 if n3 > self.n_city-3 : n3 = 0 i1 += 1 # 設定 if sw > 0 : r_m[0] = max for i1 in range(0, self.n_city) : self.seq[i1] = self.seq_w2[i1] return sw ---------------------------------- # -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * from function import Iteration #################################### # 巡回セールスマン問題(反復改善法) # coded by Y.Suganuma #################################### # 入力ミス if len(sys.argv) <= 1 : print("***error ファイル名を入力して下さい") # 入力OK else : # データの数と入力データファイル名の入力 inn = open(sys.argv[1], "r") ss = inn.readline() n = int(ss) # データの数 i_file = [] for i1 in range(0, n) : i_file.append(inn.readline().strip(" \n")) inn.close() # 実行 for i1 in range(0, n) : print("\n+++++ケース " + str(i1+1) + "+++++") # 入力と初期設定 it = Iteration (i_file[i1]) # 最適化 it.Optimize() ------------------------ケーススタディデータ------ 3 data2.txt data2.txt data3.txt ------------------データファイル(data2.txt)------------ 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 ------------------データファイル(data3.txt)------------ 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35