/******************************/
/* 巡回セールスマン問題を解く */
/* 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();
}
}
}
}