/******************************/ /* 巡回セールスマン問題を解く */ /* coded by Y.Suganuma */ /******************************/ import java.io.*; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Test { public static void main(String args[]) throws IOException { Data dt = new Data(); } } /******************************/ /* 巡回セールスマン問題を解く */ /* coded by Y.Suganuma */ /******************************/ class Data extends JFrame implements ItemListener, ActionListener { int kind = 10; // =10 : 10都市 // =20 : 20都市 JButton bt; JComboBox <String> choice; /******************/ /* コンストラクタ */ /******************/ Data() { // JFrameクラスのコンストラクタの呼び出し super("データの入力"); // レイアウトの変更 Container cp = getContentPane(); cp.setBackground(Color.white); cp.setLayout(null); JPanel jp = new JPanel(); jp.setLayout(new GridLayout(2, 2, 5, 10)); jp.setBackground(Color.white); cp.add(jp); Font f = new Font("TimesRoman", Font.BOLD, 20); // スクロールリスト(都市の数) JLabel lbl1 = new JLabel("都市の数"); lbl1.setFont(f); jp.add(lbl1); choice = new JComboBox <String> (); choice.setBackground(Color.white); choice.setFont(f); choice.addItem("10都市"); choice.addItem("20都市"); jp.add(choice); choice.addItemListener(this); // OK ボタンの設定 JLabel lbl2 = new JLabel(); jp.add(lbl2); bt = new JButton("OK"); bt.setFont(f); bt.addActionListener(this); jp.add(bt); // Windowサイズを設定 setSize(250, 150); // ウィンドウを表示 setVisible(true); Insets in = getInsets(); jp.setLocation(10, 10); jp.setSize(250-in.left-in.right-20, 150-in.top-in.bottom-20); // イベントアダプタ addWindowListener(new WinEnd()); } /******************************/ /* チョイスコントロールの処理 */ /******************************/ public void itemStateChanged(ItemEvent e) { if (e.getItemSelectable() == choice) { kind = choice.getSelectedIndex(); kind = (kind <= 0) ? 10 : 20; } } /********************************/ /* OKボタンが押されたときの処理 */ /********************************/ public void actionPerformed(ActionEvent e) { if (e.getSource() == bt) { TSP tsp = new TSP (kind); tsp.repaint(); } } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } } /************************/ /* 巡回セールスマン問題 */ /************************/ class TSP extends JFrame { private TSP tsp = this; /****************************/ /* コンストラクタ */ /* kd : =10 : 10都市 */ /* =20 : 20都市 */ /****************************/ TSP (int kd) { // Frameクラスのコンストラクタの呼び出し super("巡回セールスマン問題"); // 値の設定と領域の確保 Container cp = getContentPane(); cp.setBackground(Color.white); cp.setLayout(null); // ウィンドウを表示 setVisible(true); Draw_p dp = new Draw_p(kd, this); dp.setBackground(Color.white); cp.add(dp); // イベントアダプタ addWindowListener(new WinEnd()); } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { tsp.setVisible(false); } } } class Draw_p extends JPanel { private double ritu; // 表示倍率 private int size; // 都市を示す丸の大きさ private int font; // フォントサイズ private int min_x, max_x, min_y, max_y; // 都市の存在範囲 private int width, height; // 画面の大きさ private int yoyu_x, yoyu_y; // 表示位置 private int con[][]; // 接続状態 private int city[][]; // 各都市の位置 private int rg[][]; // 各都市間の距離 private int n_city; // 都市の数 private int pos1; // 前回マウスが押された都市 private String str; // メッセージ Draw_p (int kd, TSP tsp) { // 値の設定と領域の確保 double k1, k2, x, y; int i1, i2; n_city = kd; font = 15; size = 10; yoyu_x = 20; yoyu_y = 50; width = 1000; height = 700; pos1 = -1; str = "***Start***"; con = new int [n_city][n_city]; city = new int [n_city][2]; if (n_city == 10) { city[0][0] = -58; city[1][0] = 55; city[2][0] = 6; city[3][0] = 27; city[4][0] = 44; city[5][0] = 33; city[6][0] = -94; city[7][0] = -9; city[8][0] = 33; city[9][0] = 43; city[0][1] = 37; city[1][1] = -19; city[2][1] = -79; city[3][1] = -30; city[4][1] = -94; city[5][1] = -58; city[6][1] = 87; city[7][1] = 3; city[8][1] = 69; city[9][1] = -57; } else { city[0][0] = 31; city[1][0] = 34; city[2][0] = 3; city[3][0] = 20; city[4][0] = -48; city[5][0] = 65; city[6][0] = -40; city[7][0] = 57; city[8][0] = 60; city[9][0] = 7; city[10][0] = -50; city[11][0] = 43; city[12][0] = -34; city[13][0] = 41; city[14][0] = -65; city[15][0] = 56; city[16][0] = 19; city[17][0] = 11; city[18][0] = -20; city[19][0] = 29; city[0][1] = -39; city[1][1] = -78; city[2][1] = -2; city[3][1] = -26; city[4][1] = -25; city[5][1] = -65; city[6][1] = 28; city[7][1] = 97; city[8][1] = -7; city[9][1] = 25; city[10][1] = 40; city[11][1] = 95; city[12][1] = -10; city[13][1] = 47; city[14][1] = -96; city[15][1] = -91; city[16][1] = -50; city[17][1] = 3; city[18][1] = -63; city[19][1] = 43; } rg = new int [n_city][n_city]; for (i1 = 0; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) { x = city[i2][0] - city[i1][0]; y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(Math.sqrt(x * x + y * y) + 0.5); rg[i2][i1] = rg[i1][i2]; con[i1][i2] = 0; con[i2][i1] = 0; } rg[i1][i1] = 0; con[i1][i2] = 0; } // 描画領域の計算 min_x = (int)city[0][0]; max_x = (int)city[0][0]; min_y = (int)city[0][1]; max_y = (int)city[0][1]; for (i1 = 1; i1 < n_city; i1++) { if ((int)city[i1][0] < min_x) min_x = (int)city[i1][0]; else { if ((int)city[i1][0] > max_x) max_x = (int)city[i1][0]; } if ((int)city[i1][1] < min_y) min_y = (int)city[i1][1]; else { if ((int)city[i1][1] > max_y) max_y = (int)city[i1][1]; } } k1 = (double)(width - 2 * yoyu_x) / (max_x - min_x); k2 = (double)(height - yoyu_y - yoyu_x) / (max_y - min_y); ritu = (k1 < k2) ? k1 : k2; // サイズ width = 2 * yoyu_x + (int)(ritu * (max_x - min_x)); height = yoyu_y + yoyu_x + (int)(ritu * (max_y - min_y)); setSize(width, height); setLocation(0, 0); Insets in = tsp.getInsets(); tsp.setSize(width+in.right+in.left, height+in.top+in.bottom); // イベントアダプタ addMouseListener(new ClickMouse()); } /********/ /* 描画 */ /********/ public void paintComponent (Graphics g) { super.paintComponent(g); // 親クラスの描画(必ず必要) int i1, i2, x1, x2, y1, y2, p = size / 2, r; // メッセージ Font f = new Font("TimesRoman", Font.BOLD, font+5); g.setFont(f); g.setColor(Color.blue); // メッセージ if (str.length() > 0) g.drawString(str, yoyu_x, font+5); // 距離の出力 else { r = 0; for (i1 = 0; i1 < n_city; i1++) { for (i2 = i1+1; i2 < n_city; i2++) { if (con[i1][i2] > 0) r += rg[i1][i2]; } } g.drawString("Range : " + Integer.toString(r) + " ", yoyu_x, font+5); } // 点と直線のプロット f = new Font("TimesRoman", Font.PLAIN, font); g.setFont(f); g.setColor(Color.black); for (i1 = 0; i1 < n_city; i1++) { x1 = yoyu_x + (int)(ritu * (city[i1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - city[i1][1])); g.fillOval(x1, y1, size, size); g.drawString(Integer.toString(i1+1), x1+p, y1-p); for (i2 = i1+1; i2 < n_city; i2++) { if (con[i1][i2] > 0) { x2 = yoyu_x + (int)(ritu * (city[i2][0] - min_x)); y2 = yoyu_y + (int)(ritu * (max_y - city[i2][1])); g.drawLine(x1+p, y1+p, x2+p, y2+p); } } } } /**********************************/ /* nextボタンが押されたときの処理 */ /**********************************/ class ClickMouse extends MouseAdapter { /************************************/ /* マウスがクリックされたときの処理 */ /************************************/ public void mouseClicked(MouseEvent e) { int i1, sw, pos2, x, xp, y, yp; // マウスの位置 xp = e.getX(); yp = e.getY(); // クリックされた都市を決定 pos2 = -1; for (i1 = 0; i1 < n_city && pos2 < 0; i1++) { x = yoyu_x + (int)(ritu * (city[i1][0] - min_x)); y = yoyu_y + (int)(ritu * (max_y - city[i1][1])); if (xp > x && xp < x+size && yp > y && yp < y+size) pos2 = i1; } if (pos2 >= 0) { // 最初のクリック if (pos1 < 0) { str = "Next Position ?"; pos1 = pos2; } // 2回目のクリック else { if (con[pos1][pos2] > 0) { con[pos1][pos2] = 0; con[pos2][pos1] = 0; } else { con[pos1][pos2] = 1; con[pos2][pos1] = 1; } str = ""; pos1 = -1; } repaint(); } } } }