433 lines
122 KiB
Plaintext
433 lines
122 KiB
Plaintext
![]() |
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 4,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/html": [
|
||
|
"<div>\n",
|
||
|
"<style scoped>\n",
|
||
|
" .dataframe tbody tr th:only-of-type {\n",
|
||
|
" vertical-align: middle;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe tbody tr th {\n",
|
||
|
" vertical-align: top;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe thead th {\n",
|
||
|
" text-align: right;\n",
|
||
|
" }\n",
|
||
|
"</style>\n",
|
||
|
"<table border=\"1\" class=\"dataframe\">\n",
|
||
|
" <thead>\n",
|
||
|
" <tr style=\"text-align: right;\">\n",
|
||
|
" <th></th>\n",
|
||
|
" <th>File Name</th>\n",
|
||
|
" <th>Line 1</th>\n",
|
||
|
" <th>Line 2</th>\n",
|
||
|
" <th>Line 3</th>\n",
|
||
|
" <th>Line 4</th>\n",
|
||
|
" <th>Line 5</th>\n",
|
||
|
" <th>Line 6</th>\n",
|
||
|
" </tr>\n",
|
||
|
" </thead>\n",
|
||
|
" <tbody>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>0</th>\n",
|
||
|
" <td>CHN144.tsp</td>\n",
|
||
|
" <td>NAME : CHN144</td>\n",
|
||
|
" <td>COMMENT : China 144-city problem</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 144</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>1</th>\n",
|
||
|
" <td>eil101.tsp</td>\n",
|
||
|
" <td>NAME : eil101</td>\n",
|
||
|
" <td>COMMENT : 101-city problem (Christofides/Eilon)</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 101</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>2</th>\n",
|
||
|
" <td>eil76.tsp</td>\n",
|
||
|
" <td>NAME: eil76</td>\n",
|
||
|
" <td>TYPE: TSP</td>\n",
|
||
|
" <td>COMMENT: 76-city problem (Christofides/Eilon)</td>\n",
|
||
|
" <td>DIMENSION: 76</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE: EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>3</th>\n",
|
||
|
" <td>GR96.tsp</td>\n",
|
||
|
" <td>NAME: gr96</td>\n",
|
||
|
" <td>TYPE: TSP</td>\n",
|
||
|
" <td>COMMENT: Africa-Subproblem of 666-city TSP (Gr...</td>\n",
|
||
|
" <td>DIMENSION: 96</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE: GEO</td>\n",
|
||
|
" <td>DISPLAY_DATA_TYPE: COORD_DISPLAY</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>4</th>\n",
|
||
|
" <td>PBK411.tsp</td>\n",
|
||
|
" <td>NAME : pbk411</td>\n",
|
||
|
" <td>COMMENT : Bonn VLSI data set with 411 points</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 411</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>5</th>\n",
|
||
|
" <td>PR76.tsp</td>\n",
|
||
|
" <td>NAME : pr76</td>\n",
|
||
|
" <td>COMMENT : 76-city problem (Padberg/Rinaldi)</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 76</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>6</th>\n",
|
||
|
" <td>RBU737.tsp</td>\n",
|
||
|
" <td>NAME : rbu737</td>\n",
|
||
|
" <td>COMMENT : Bonn VLSI data set with 737 points</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 737</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>7</th>\n",
|
||
|
" <td>ulysses16.tsp</td>\n",
|
||
|
" <td>NAME: ulysses16.tsp</td>\n",
|
||
|
" <td>TYPE: TSP</td>\n",
|
||
|
" <td>COMMENT: Odyssey of Ulysses (Groetschel/Padberg)</td>\n",
|
||
|
" <td>DIMENSION: 16</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE: GEO</td>\n",
|
||
|
" <td>DISPLAY_DATA_TYPE: COORD_DISPLAY</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>8</th>\n",
|
||
|
" <td>ulysses8.tsp</td>\n",
|
||
|
" <td>NAME: ulysses16.tsp</td>\n",
|
||
|
" <td>TYPE: TSP</td>\n",
|
||
|
" <td>COMMENT: Odyssey of Ulysses (Groetschel/Padberg)</td>\n",
|
||
|
" <td>DIMENSION: 8</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE: GEO</td>\n",
|
||
|
" <td>DISPLAY_DATA_TYPE: COORD_DISPLAY</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>9</th>\n",
|
||
|
" <td>XIT1083.tsp</td>\n",
|
||
|
" <td>NAME : xit1083</td>\n",
|
||
|
" <td>COMMENT : Bonn VLSI data set with 1083 points</td>\n",
|
||
|
" <td>TYPE : TSP</td>\n",
|
||
|
" <td>DIMENSION : 1083</td>\n",
|
||
|
" <td>EDGE_WEIGHT_TYPE : EUC_2D</td>\n",
|
||
|
" <td>NODE_COORD_SECTION</td>\n",
|
||
|
" </tr>\n",
|
||
|
" </tbody>\n",
|
||
|
"</table>\n",
|
||
|
"</div>"
|
||
|
],
|
||
|
"text/plain": [
|
||
|
" File Name Line 1 \\\n",
|
||
|
"0 CHN144.tsp NAME : CHN144 \n",
|
||
|
"1 eil101.tsp NAME : eil101 \n",
|
||
|
"2 eil76.tsp NAME: eil76 \n",
|
||
|
"3 GR96.tsp NAME: gr96 \n",
|
||
|
"4 PBK411.tsp NAME : pbk411 \n",
|
||
|
"5 PR76.tsp NAME : pr76 \n",
|
||
|
"6 RBU737.tsp NAME : rbu737 \n",
|
||
|
"7 ulysses16.tsp NAME: ulysses16.tsp \n",
|
||
|
"8 ulysses8.tsp NAME: ulysses16.tsp \n",
|
||
|
"9 XIT1083.tsp NAME : xit1083 \n",
|
||
|
"\n",
|
||
|
" Line 2 \\\n",
|
||
|
"0 COMMENT : China 144-city problem \n",
|
||
|
"1 COMMENT : 101-city problem (Christofides/Eilon) \n",
|
||
|
"2 TYPE: TSP \n",
|
||
|
"3 TYPE: TSP \n",
|
||
|
"4 COMMENT : Bonn VLSI data set with 411 points \n",
|
||
|
"5 COMMENT : 76-city problem (Padberg/Rinaldi) \n",
|
||
|
"6 COMMENT : Bonn VLSI data set with 737 points \n",
|
||
|
"7 TYPE: TSP \n",
|
||
|
"8 TYPE: TSP \n",
|
||
|
"9 COMMENT : Bonn VLSI data set with 1083 points \n",
|
||
|
"\n",
|
||
|
" Line 3 Line 4 \\\n",
|
||
|
"0 TYPE : TSP DIMENSION : 144 \n",
|
||
|
"1 TYPE : TSP DIMENSION : 101 \n",
|
||
|
"2 COMMENT: 76-city problem (Christofides/Eilon) DIMENSION: 76 \n",
|
||
|
"3 COMMENT: Africa-Subproblem of 666-city TSP (Gr... DIMENSION: 96 \n",
|
||
|
"4 TYPE : TSP DIMENSION : 411 \n",
|
||
|
"5 TYPE : TSP DIMENSION : 76 \n",
|
||
|
"6 TYPE : TSP DIMENSION : 737 \n",
|
||
|
"7 COMMENT: Odyssey of Ulysses (Groetschel/Padberg) DIMENSION: 16 \n",
|
||
|
"8 COMMENT: Odyssey of Ulysses (Groetschel/Padberg) DIMENSION: 8 \n",
|
||
|
"9 TYPE : TSP DIMENSION : 1083 \n",
|
||
|
"\n",
|
||
|
" Line 5 Line 6 \n",
|
||
|
"0 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION \n",
|
||
|
"1 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION \n",
|
||
|
"2 EDGE_WEIGHT_TYPE: EUC_2D NODE_COORD_SECTION \n",
|
||
|
"3 EDGE_WEIGHT_TYPE: GEO DISPLAY_DATA_TYPE: COORD_DISPLAY \n",
|
||
|
"4 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION \n",
|
||
|
"5 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION \n",
|
||
|
"6 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION \n",
|
||
|
"7 EDGE_WEIGHT_TYPE: GEO DISPLAY_DATA_TYPE: COORD_DISPLAY \n",
|
||
|
"8 EDGE_WEIGHT_TYPE: GEO DISPLAY_DATA_TYPE: COORD_DISPLAY \n",
|
||
|
"9 EDGE_WEIGHT_TYPE : EUC_2D NODE_COORD_SECTION "
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 4,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"import os\n",
|
||
|
"import pandas as pd\n",
|
||
|
"\n",
|
||
|
"# 定义文件夹路径\n",
|
||
|
"folder_path = './data'\n",
|
||
|
"\n",
|
||
|
"# 初始化一个空的DataFrame来存储信息\n",
|
||
|
"columns = ['File Name', 'Line 1', 'Line 2', 'Line 3', 'Line 4', 'Line 5', 'Line 6']\n",
|
||
|
"df = pd.DataFrame(columns=columns)\n",
|
||
|
"\n",
|
||
|
"# 遍历文件夹中的所有文件\n",
|
||
|
"for file_name in os.listdir(folder_path):\n",
|
||
|
" if file_name.endswith('.tsp'):\n",
|
||
|
" file_path = os.path.join(folder_path, file_name)\n",
|
||
|
" with open(file_path, 'r') as file:\n",
|
||
|
" lines = file.readlines()\n",
|
||
|
" # 取前六行作为基本信息\n",
|
||
|
" basic_info = lines[:6]\n",
|
||
|
" # 如果行数不足六行,用空字符串填充\n",
|
||
|
" while len(basic_info) < 6:\n",
|
||
|
" basic_info.append('')\n",
|
||
|
" # 将信息添加到DataFrame中\n",
|
||
|
" new_row = pd.DataFrame({\n",
|
||
|
" 'File Name': [file_name],\n",
|
||
|
" 'Line 1': [basic_info[0].strip()],\n",
|
||
|
" 'Line 2': [basic_info[1].strip()],\n",
|
||
|
" 'Line 3': [basic_info[2].strip()],\n",
|
||
|
" 'Line 4': [basic_info[3].strip()],\n",
|
||
|
" 'Line 5': [basic_info[4].strip()],\n",
|
||
|
" 'Line 6': [basic_info[5].strip()]\n",
|
||
|
" })\n",
|
||
|
" df = pd.concat([df, new_row], ignore_index=True)\n",
|
||
|
"\n",
|
||
|
"# 显示表格\n",
|
||
|
"df\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 25,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxIAAAMWCAYAAABlVbDdAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnQeUFGX29p8J5JxzRpAgQUBBMgIiKAIqIoIgoGD+dM2r6/pfXXfXsIZVTCiSjCiIBCWDgiAgqCQlgyA555np7zxvTc30DD0z3TOdqvr5ndOnq7uru9/qqq5b9733PjfO4/F4IIQQQgghhBABEB/IykIIIYQQQghB5EgIIYQQQgghAkaOhBBCCCGEECJg5EgIIYQQQgghAkaOhBBCCCGEECJg5EgIIYQQQgghAkaOhBBCCCGEECJg5EgIIYQQQgghAkaOhIg69u3bh0WLFkV6GEIIIaIM2Qchogs5Ei7h4MGDcAMffPABKlSogCuvvNIYDCGEEHlD9kEIESriPB6PJ2SfLvLMm2++iTVr1uDtt9/Ocp0jR46gcuXKGDBgAO666y60bNnSr89esWKFeU92fPXVV2jYsCEuv/zyHI0RD6WkpCScOXMGLVq0wIwZMxAop0+fRpUqVXD48GG89tpruPfeewP+DCGEiAVkH2QfhIg0iZEegMia33//HQ888ADOnTtnTp5/+9vffK73zTffmBMsZ2tuuukmvz+fJ/XNmzejZMmSqF+/fobX1q1bh+PHj5uTP9m7dy+2b9+OihUrIiEhIcvPPH/+vBnL2bNnMzw/ceJEfPzxxyhSpAgSE7M/7AoVKmQMxYsvvohly5Zla5T42/D7/v3vf6Np06Z+b7sQQjgZ2QfZByGiATkSUcxFF12Ed999F0OGDMHf//53NGnSBH369Llgvc8++8zcX3fddbjqqqv8/vz8+fOb+7Zt2+Lrr7/O8FqnTp2wcOHCtHUKFChg7pcuXYqaNWsGvC3btm3DnDlzjBHIly+fMTbx8b4z6+Li4oxhTE5OxoIFCy54PSUlxRgIGiX7nrNusQyNJn/PrH7TYMD9R4O8ZMkSY5xp9Lt27YpHHnkEbdq0Cdn3CiEuRPbBufaBY+QtJ6dJCEfA1CYR3YwaNYrTPp5y5cp5Tp8+neG1w4cPewoWLOiJi4vz/PzzzwF97i+//GI+t1evXhe81rFjR/Patm3bzOMGDRqYx1u3bvUEm2PHjnkOHTqU5es//PCD5/rrr/ds377dE60cPXrUEx8fb36jrG7Dhw/Pch9kd/vHP/7h8zsnTZrkueKKKzyFCxc26yUkJHhatmxpng82Y8aMMccYv6dYsWKeunXrehITE9O+d/z48Tl+xoIFCzz58+f3PP3000EfnxCxiuxD9NsHe5zXXXedp3Tp0mnn9tq1a3v+7//+74L95s2sWbM8/fv391StWtWcP3k/ZMiQHPfnn3/+aY4N+33169f3/Pe///UkJycHfdv4+2dnw2gjcoJ2i8fpBx98EPTxidAiR8IBnDhxwtOwYUPPF198ccFr//vf/8wftXfv3gF/7saNG3M0FLt37zaPGzVqFBJDwZNa3759zYmuX79+nqlTp3rOnz+f9vobb7zhKVCggPnukiVLelasWOGJRmbPnm3GSGeC4/V140k9M++++27aiTar9z3//PMXvG/EiBFpJ2leQLRt29bc28/95S9/Cdq2bdiwwVOoUCFzkn/hhRc8586dM8/v3bvX06dPn7R9s3///iw/Y/369Z5SpUqZdeVICBE8ZB+i3z6MHTvWnOM5Tk78tG7d2jgR9vmaE0JnzpzJ8J6zZ896br755gsuyO1lTuRw//qCDh4dCHtdexKIt1tvvTXo21elShXz2VnZsCJFimT7/oULF6btRzkSzkOORJRi/zHzctuzZ0+OF4g5GYo//vgjqIbiyJEjZvaCN544Oet14403ZrgIrlixoufRRx8147JPmPfee6/n999/T/uc119/3XP//fd7li5d6okGnn32WTPWu+++O6D32Q4BL9D95c0330wzSO+//74nJSXFPH/q1CljJOzfcfHixZ5gQAPOz3v44YcveI0zafYMG42lL3766SdP9erV08YlR0KIvCH74Bz7sHr1auMI2RM8x48fN8/zvG07er4iz1zXnpx67LHHzMQNHSs6S+3atUt73+TJkzO8jxM9dCz5WpkyZTxTpkzxJCUlmf3ZrFkz8/zHH38ctO3btWtXWqTatkWBMGfOnLRJJjkSzkQJelGKnXN67bXXonjx4gHlyn/yyScZPiMrmGNK9u/fj1mzZmV47dChQ2mfF0yY+zp58mST58pc2MaNG+PTTz81xXE//vgjPvroI7zxxhsmF9+GOfjPPPNMhnzSmTNnGtWP1q1bm1uksYv+/FVEye37Tp48iSeffNIsf/7557j66qvTXmN+8XvvvWd+G+5T/pbt2rVDXmBRI2siWA/x17/+9YLXCxYsaAoxmRu9e/fuC15nEeXtt99uiiupHONrHSFEYMg+OMc+cHys1eC997i5jXfffTdmz56NqVOnmm2zz+179uzBq6++apYfeughPP/882nvo+IV9wdtxoYNG/D000+jX79+aa+/8847phien//ll1+iffv25nmep/nb8v7//b//hxtuuCHbwvhAbdill15qvjMQWDD/2GOPmX1drlw5c6wJBxJpT0b4xs45ZUpIIHC2w/bsT548me26y5cvz3HWyv5+e8aJ4VjmWmZ34yxSVnDGgp/DVBnvWe2vv/7aM2jQIBMC5etdu3Y14V97HDVr1jSzTPY2MWeUz3/11VeeaMCeMQtkfzH3l7NNDFfbs1Q5wdmobt26eQYPHpzlOvztOBamHQULjjUrqlWrZr6P0RFv1q5dmzZTxf3EvF5FJITIO7IPzrAPTDvjebhVq1ZmObtoNlOzbEaPHp0WbcmqPuTFF19M235v+9G4cWPz3LXXXuvzfYzw8PVFixZ5gsFDDz1kPo9RokCYPn16WoSJkSM7yqWIhPNQRCJKyWm2KBifUbVqVbz++utpjzkzQl3wQYMGGV1wUrZs2Qzv2bJlS47fm90shz1jYStyUPKPqiOcseFz11xzDf7yl7+gQ4cO5vXVq1fjH//4B7744gujGU699B9++CHtcwKdAQkFmzZtMjMp5cuXx8UXXxzQTA6VO1q1aoWiRYv69R7ORn377bfZrmPP+jOKECyKFSvm83nOeO3cudOot3hHRwj3affu3c0MWY0aNcxsmBAi78g+OMM+8BzMc2Sg52tK+xJK1pYqVcrn+6pVq5a2fOzYMWNDGEH+9ddfzXP9+/f3+b6ePXsaJS9GbexoRV5gNJrY+8RfqKY1cOBAE3nJfBwJZyFHwsXkdBKtVKkS7rnnnrTHJ06cMIaCXUOHDh3q8z1bt27NUt6PeuNHjx5NkwT0BzY82rhxozEUd9xxh7ng9KZZs2bmApRSg2PGjDGh4UAvkMeOHYvbbrstx/Hn9URapkwZ3HzzzSYViLrqNACURWVqT+aLbO/30bBStpGhezZ1Yoi3Y8eOJuwdqKwqQ90MaxPux1DBplIffvihCbuTf/7zn0ZD3ptGjRoZDXshRPQh+xAe+5BT+hjTmjKfr+3fiOmqWWGnAXFd2h57UssmK9tBmWDbVuQVOgMrV640y5QIfvzxx81vyGOLKVRMn+IxVLhwYZ8ODSWJhfORIxGl2PmpeYF56dmdiEJFdjNONAj22Diz5Y2vHPzMPPzww+aes07+5uhyPPbsWyhmqOg4kPXr1+O3334zJ+p69eqZx5yN4o0dZZnb6+t93BbWGlxyySXm5MsZJdYWTJo0yeTGPvroo36PhbNzhBf1OXWlzS00UD///DNOnTplclv/+9//mpzbzPA1IUTwkX1wjn3Ijvfffx9//PGHWfY+h9rOzC+//GK2wVe/icWLF5v7zp07p43f7i7Oc29WDhEj53bvjryyatUqM6lERo8ebRy9yy67zIyDndE5OcaINMdKx9Qb2Qf3IEciSrH/nGwgFMgfzu406o+hYLEuZyW6dOmCK664AuGAM1KEJ0deLOcVhnRzYvD
|
||
|
"text/plain": [
|
||
|
"<Figure size 800x800 with 2 Axes>"
|
||
|
]
|
||
|
},
|
||
|
"metadata": {},
|
||
|
"output_type": "display_data"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"import numpy as np\n",
|
||
|
"import matplotlib.pyplot as plt\n",
|
||
|
"from matplotlib.path import Path\n",
|
||
|
"import matplotlib.patches as patches\n",
|
||
|
"import os\n",
|
||
|
"\n",
|
||
|
"# 确保plot文件夹存在\n",
|
||
|
"if not os.path.exists('./plot'):\n",
|
||
|
" os.makedirs('./plot')\n",
|
||
|
"\n",
|
||
|
"# 设置中文显示\n",
|
||
|
"plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签\n",
|
||
|
"plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号\n",
|
||
|
"\n",
|
||
|
"# 生成10个随机分布的节点\n",
|
||
|
"np.random.seed(2025)\n",
|
||
|
"n_points = 10\n",
|
||
|
"points = np.random.rand(n_points, 2) * 100\n",
|
||
|
"\n",
|
||
|
"# 计算两点间距离的函数\n",
|
||
|
"def calculate_distance(route):\n",
|
||
|
" total = 0\n",
|
||
|
" for i in range(len(route)):\n",
|
||
|
" j = (i + 1) % len(route)\n",
|
||
|
" city1 = points[route[i]]\n",
|
||
|
" city2 = points[route[j]]\n",
|
||
|
" total += np.sqrt(np.sum((city1 - city2) ** 2))\n",
|
||
|
" return total\n",
|
||
|
"\n",
|
||
|
"# 生成随机解\n",
|
||
|
"random_solution = list(range(n_points))\n",
|
||
|
"np.random.shuffle(random_solution)\n",
|
||
|
"random_distance = calculate_distance(random_solution)\n",
|
||
|
"\n",
|
||
|
"# 使用启发式算法求解TSP问题\n",
|
||
|
"def heuristic_solution():\n",
|
||
|
" n = n_points\n",
|
||
|
" # 初始解:从城市0开始\n",
|
||
|
" current_solution = [0]\n",
|
||
|
" unvisited = set(range(1, n))\n",
|
||
|
" \n",
|
||
|
" # 不断选择最近的未访问城市\n",
|
||
|
" while unvisited:\n",
|
||
|
" current = current_solution[-1]\n",
|
||
|
" # 找到距离当前城市最近的未访问城市\n",
|
||
|
" next_city = min(unvisited, \n",
|
||
|
" key=lambda x: np.sqrt(np.sum((points[current] - points[x]) ** 2)))\n",
|
||
|
" current_solution.append(next_city)\n",
|
||
|
" unvisited.remove(next_city)\n",
|
||
|
" \n",
|
||
|
" # 2-opt局部搜索优化\n",
|
||
|
" improved = True\n",
|
||
|
" while improved:\n",
|
||
|
" improved = False\n",
|
||
|
" for i in range(n-2):\n",
|
||
|
" for j in range(i+2, n):\n",
|
||
|
" # 计算当前路径长度\n",
|
||
|
" old_distance = (\n",
|
||
|
" np.sqrt(np.sum((points[current_solution[i]] - points[current_solution[i+1]]) ** 2)) +\n",
|
||
|
" np.sqrt(np.sum((points[current_solution[j]] - points[current_solution[(j+1)%n]]) ** 2))\n",
|
||
|
" )\n",
|
||
|
" # 计算交换后的路径长度\n",
|
||
|
" new_distance = (\n",
|
||
|
" np.sqrt(np.sum((points[current_solution[i]] - points[current_solution[j]]) ** 2)) +\n",
|
||
|
" np.sqrt(np.sum((points[current_solution[i+1]] - points[current_solution[(j+1)%n]]) ** 2))\n",
|
||
|
" )\n",
|
||
|
" \n",
|
||
|
" if new_distance < old_distance:\n",
|
||
|
" # 如果交换后更优,则进行2-opt交换\n",
|
||
|
" current_solution[i+1:j+1] = reversed(current_solution[i+1:j+1])\n",
|
||
|
" improved = True\n",
|
||
|
" break\n",
|
||
|
" if improved:\n",
|
||
|
" break\n",
|
||
|
" \n",
|
||
|
" # 添加回到起点\n",
|
||
|
" current_solution.append(0)\n",
|
||
|
" return current_solution\n",
|
||
|
"\n",
|
||
|
"better_solution = heuristic_solution()\n",
|
||
|
"better_distance = calculate_distance(better_solution)\n",
|
||
|
"\n",
|
||
|
"# 创建并保存随机解图\n",
|
||
|
"plt.figure(figsize=(8, 8))\n",
|
||
|
"ax1 = plt.gca()\n",
|
||
|
"for i, point in enumerate(points):\n",
|
||
|
" ax1.scatter(point[0], point[1], c='blue', s=100)\n",
|
||
|
" ax1.annotate(f'城市{i}', (point[0], point[1]), xytext=(5, 5), textcoords='offset points',fontsize = 16)\n",
|
||
|
"\n",
|
||
|
"for i in range(len(random_solution)):\n",
|
||
|
" j = (i + 1) % len(random_solution)\n",
|
||
|
" city1 = points[random_solution[i]]\n",
|
||
|
" city2 = points[random_solution[j]]\n",
|
||
|
" ax1.plot([city1[0], city2[0]], [city1[1], city2[1]], 'r-')\n",
|
||
|
"\n",
|
||
|
"ax1.set_title(f'总距离: {random_distance:.2f}',fontsize = 20)\n",
|
||
|
"ax1.grid(True)\n",
|
||
|
"ax1.margins(0.13)\n",
|
||
|
"plt.savefig('./plot/random_solution.png',dpi=300)\n",
|
||
|
"plt.close()\n",
|
||
|
"\n",
|
||
|
"# 创建并保存贪心解图\n",
|
||
|
"plt.figure(figsize=(8, 8))\n",
|
||
|
"ax2 = plt.gca()\n",
|
||
|
"for i, point in enumerate(points):\n",
|
||
|
" ax2.scatter(point[0], point[1], c='blue', s=100)\n",
|
||
|
" ax2.annotate(f'城市{i}', (point[0], point[1]), xytext=(5, 5), textcoords='offset points',fontsize = 16)\n",
|
||
|
"\n",
|
||
|
"for i in range(len(better_solution)):\n",
|
||
|
" j = (i + 1) % len(better_solution)\n",
|
||
|
" city1 = points[better_solution[i]]\n",
|
||
|
" city2 = points[better_solution[j]]\n",
|
||
|
" ax2.plot([city1[0], city2[0]], [city1[1], city2[1]], 'g-')\n",
|
||
|
"\n",
|
||
|
"ax2.set_title(f'总距离: {better_distance:.2f}',fontsize = 20)\n",
|
||
|
"ax2.grid(True)\n",
|
||
|
"ax2.margins(0.13)\n",
|
||
|
"plt.savefig('./plot/better_solution.png')\n",
|
||
|
"plt.close()\n",
|
||
|
"\n",
|
||
|
"# 显示两个图\n",
|
||
|
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 8))\n",
|
||
|
"\n",
|
||
|
"# 绘制随机解\n",
|
||
|
"for i, point in enumerate(points):\n",
|
||
|
" ax1.scatter(point[0], point[1], c='blue', s=100)\n",
|
||
|
" ax1.annotate(f'城市{i}', (point[0], point[1]), xytext=(5, 5), textcoords='offset points',fontsize = 16)\n",
|
||
|
"\n",
|
||
|
"for i in range(len(random_solution)):\n",
|
||
|
" j = (i + 1) % len(random_solution)\n",
|
||
|
" city1 = points[random_solution[i]]\n",
|
||
|
" city2 = points[random_solution[j]]\n",
|
||
|
" ax1.plot([city1[0], city2[0]], [city1[1], city2[1]], 'r-')\n",
|
||
|
"\n",
|
||
|
"ax1.set_title(f'总距离: {random_distance:.2f}',fontsize = 20)\n",
|
||
|
"ax1.grid(True)\n",
|
||
|
"ax1.margins(0.13)\n",
|
||
|
"\n",
|
||
|
"# 绘制贪心解\n",
|
||
|
"for i, point in enumerate(points):\n",
|
||
|
" ax2.scatter(point[0], point[1], c='blue', s=100)\n",
|
||
|
" ax2.annotate(f'城市{i}', (point[0], point[1]), xytext=(5, 5), textcoords='offset points',fontsize = 16)\n",
|
||
|
"\n",
|
||
|
"for i in range(len(better_solution)):\n",
|
||
|
" j = (i + 1) % len(better_solution)\n",
|
||
|
" city1 = points[better_solution[i]]\n",
|
||
|
" city2 = points[better_solution[j]]\n",
|
||
|
" ax2.plot([city1[0], city2[0]], [city1[1], city2[1]], 'g-')\n",
|
||
|
"\n",
|
||
|
"ax2.set_title(f'总距离: {better_distance:.2f}',fontsize = 20)\n",
|
||
|
"ax2.grid(True)\n",
|
||
|
"ax2.margins(0.13)\n",
|
||
|
"\n",
|
||
|
"plt.tight_layout()\n",
|
||
|
"plt.show()"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": "lead",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.11.11"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 2
|
||
|
}
|