我目前正在编写模拟退火代码来解决旅行推销员问题,并且在存储和使用我从 txt 文件中读取的数据时遇到了困难。文件中的每一行和每一列代表每个城市,两个不同城市之间的距离存储为一个 15 x 15 矩阵:
0.0 5.0 5.0 6.0 7.0 2.0 5.0 2.0 1.0 5.0 5.0 1.0 2.0 7.1 5.0
5.0 0.0 5.0 5.0 5.0 2.0 5.0 1.0 5.0 6.0 6.0 6.0 6.0 1.0 7.1
5.0 5.0 0.0 6.0 1.0 6.0 5.0 5.0 1.0 6.0 5.0 7.0 1.0 5.0 6.0
6.0 5.0 6.0 0.0 5.0 2.0 1.0 6.0 5.0 6.0 2.0 1.0 2.0 1.0 5.0
7.0 5.0 1.0 5.0 0.0 7.0 1.0 1.0 2.0 1.0 5.0 6.0 2.0 2.0 5.0
2.0 2.0 6.0 2.0 7.0 0.0 5.0 5.0 6.0 5.0 2.0 5.0 1.0 2.0 5.0
5.0 5.0 5.0 1.0 1.0 5.0 0.0 2.0 6.0 1.0 5.0 7.0 5.0 1.0 6.0
2.0 1.0 5.0 6.0 1.0 5.0 2.0 0.0 7.0 6.0 2.0 1.0 1.0 5.0 2.0
1.0 5.0 1.0 5.0 2.0 6.0 6.0 7.0 0.0 5.0 5.0 5.0 1.0 6.0 6.0
5.0 6.0 6.0 6.0 1.0 5.0 1.0 6.0 5.0 0.0 7.0 1.0 2.0 5.0 2.0
5.0 6.0 5.0 2.0 5.0 2.0 5.0 2.0 5.0 7.0 0.0 2.0 1.0 2.0 1.0
1.0 6.0 7.0 1.0 6.0 5.0 7.0 1.0 5.0 1.0 2.0 0.0 5.0 6.0 5.0
2.0 6.0 1.0 2.0 2.0 1.0 5.0 1.0 1.0 2.0 1.0 5.0 0.0 7.0 6.0
7.0 1.0 5.0 1.0 2.0 2.0 1.0 5.0 6.0 5.0 2.0 6.0 7.0 0.0 5.0
5.0 7.0 6.0 5.0 5.0 5.0 6.0 2.0 6.0 2.0 1.0 5.0 6.0 5.0 0.0
要阅读这篇文章,我有一个 LoadCities() 函数,如下所示:
#include "iostream"
#include "fstream"
#include "string"
using namespace std;
double distances [15][15];
void LoadCities()
{
ifstream CityFile;
if (!CityFile.is_open()) //check is file has been opened
{
CityFile.open ("Cities.txt", ios::in | ios::out);
if (!CityFile)
{
cerr << "Failed to open " << CityFile << endl;
exit(EXIT_FAILURE); //abort program
}
}
int length;
char * buffer;
string cities;
CityFile.seekg(0, ios::end);
length = CityFile.tellg();
CityFile.seekg (0, ios::beg);
buffer = new char [length];
cities = CityFile.read (buffer,length);
string rows = strtok(cities, "\n");
distances = new double[rows.length()][rows.length()];
for (int i = 0; i < (string) rows.length(); i++)
{
string distance = strtok(rows[i], " ");
for (int j = 0; j < distance.length(); j++)
{
distances[i][j] = (double) Parse(distance[j]);
}
}
CityFile.close();
}
我尝试了另一种 istreambuf_iterator 方法来将读取的材料操作到数组中,但是我似乎总是遇到并发症:
ifstream CityFile("Cities.txt");
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>());
任何帮助将不胜感激。一直在抨击我的头,但收效甚微!
################ 编辑/更新@SoapBox - SA 代码、函数和 main() 的一些细节。这不干净、不高效、不整洁,也不适合现阶段,只需要暂时工作。这个版本(下)工作并设置为解决多项式(最简单的问题)。将其转换为旅行推销员问题需要做的是:
编写 LoadCities() 函数来收集距离数据。(当前的)
更改 Initialise() 以获得所涉及的距离的总和
将 E() 更改为 TSP 函数(例如计算随机路线的距离)
后两个我知道我可以做到,但是我需要 LoadCities() 来做到这一点。在以下脚本中无需更改任何其他内容。
#include "math.h"
#include "iostream"
#include "fstream"
#include "time.h" // Define time()
#include "stdio.h" // Define printf()
#include "randomc.h" // Define classes for random number generators
#include "mersenne.cpp" // Include code for the chosen random number generator
using namespace std; // For the use of text generation in application
double T;
double T_initial;
double S;
double S_initial;
double S_current;
double S_trial;
double E_current;
int N_step; // Number of Iterations for State Search per Temperature
int N_max; //Number of Iterations for Temperature
int Write;
const double EXP = 2.718281828;
//------------------------------------------------------------------------------
//Problem Function of Primary Variable (Debugged 17/02/09 - Works as intended)
double E(double x) //ORIGNINAL
{
double y = x*x - 6*x + 2;
return y;
}
//------------------------------------------------------------------------------
//Random Number Generation Function (Mod 19/02/09 - Generated integers only & fixed sequence)
double Random_Number_Generator(double nHigh, double nLow)
{
int seed = (int)time(0); // Random seed
CRandomMersenne RanGen(seed); // Make instance of random number generator
double fr; // Random floating point number
fr = ((RanGen.Random() * (nHigh - nLow)) + nLow); // Generatres Random Interger between nLow & nHigh
return fr;
}
//------------------------------------------------------------------------------
//Initializing Function (Temp 17/02/09)
void Initialize() //E.g. Getting total Distance between Cities
{
S_initial = Random_Number_Generator(10, -10);
cout << "S_Initial: " << S_initial << endl;
}
//------------------------------------------------------------------------------
//Cooling Schedule Function (make variables) (Completed 16/02/09)
double Schedule(double Temp, int i) // Need to find cooling schedule
{
double CoolingRate = 0.9999;
return Temp *= CoolingRate;
}
//------------------------------------------------------------------------------
//Next State Function (Mod 18/02/09)
double Next_State(double T_current, int i)
{
S_trial = Random_Number_Generator(pow(3, 0.5), pow(3, 0.5)*-1);
S_trial += S_current;
double E_t = E(S_trial);
double E_c = E(S_current);
double deltaE = E_t - E_c; //Defines gradient of movement
if ( deltaE <= 0 ) //Downhill
{
S_current = S_trial;
E_current = E_t;
}
else //Uphill
{
double R = Random_Number_Generator(1,0); //pseudo random number generated
double Ratio = 1-(float)i/(float)N_max; //Control Parameter Convergence to 0
double ctrl_pram = pow(EXP, (-deltaE / T_current)); //Control Parameter
if (R < ctrl_pram*Ratio) //Checking
{
S_current = S_trial; //Expresses probability of uphill acceptance
E_current = E_t;
}
else
E_current = E_c;
}
return S_current;
}
//------------------------------------------------------------------------------
//Metropolis Function (Mod 18/02/09)
double Metropolis(double S_start, double T_current, int N_Steps, int N_temperatures)
{
S_current = S_start; //Initialised S_initial equated to S_current
for ( int i=1; i <= N_step; i++ ) //Iteration of neighbour states
S_current = Next_State(T_current, N_temperatures); //Determines acceptance of new states
return S_current;
}
//------------------------------------------------------------------------------
//Write Results to Notepad (Completed 18/02/09)
void WriteResults(double i, double T, double x, double y)
{
//This function opens a results file (if not already opened)
//and stores results for one time step
static ofstream OutputFile;
const int MAXLENGTH = 80;
if (!OutputFile.is_open()) //check is file has been opened
{
//no it hasn't. Get a file name and open it.
char FileName[MAXLENGTH];
//read file name
cout << "Enter file name: ";
do
{
cin.getline(FileName, MAXLENGTH);
}
while (strlen(FileName) <= 0); //try again if length of string is 0
//open file
OutputFile.open(FileName);
// check if file was opened successfully
if (!OutputFile)
{
cerr << "Failed to open " << FileName << endl;
exit(EXIT_FAILURE); //abort program
}
OutputFile << "Iterations" << '\t' << "Temperatures" << '\t' << "X-Value" << '\t' << "Y-Value" << endl;
OutputFile << endl;
}
//OutputFile.width(10);
OutputFile << i << '\t' << T << '\t' << x << '\t' << y << endl;
if (i == N_max)
{
OutputFile << endl
<< "Settings: " << endl
<< "Initial Temperature: " << T_initial << endl
<< "Temperature Iterations: " << N_max << endl
<< "Step Iterations: " << N_step << endl
<< endl
<< "Results: " << endl
<< "Final Temperature: " << T << endl
<< "Minimum: " << S << endl;
OutputFile.close();
}
}
//------------------------------------------------------------------------------
//Main SA Function (Mod 17/02/09)
void SA(int W)
{
S = S_initial;
T = T_initial;
for ( int N_temperatures = 1 ; N_temperatures <= N_max ; N_temperatures++ )
{
S = Metropolis( S, T, N_step, N_temperatures);
T = Schedule(T, N_temperatures);
if (W == 1)
WriteResults(N_temperatures, T, S, E_current);
}
cout << "Result" << endl
<< "Y-value> " << S << endl
<< "Temperature> " << T << endl;
}
//------------------------------------------------------------------------------
//Execution of Traveling Salesman Problem (Progress 18/02/09)
int main()
{
cout << "Quadratic Function" << endl
<< "Solving method: Simulated Annealing" << endl;
cout << "" << endl;
cout << "Select desired Initial Temperature:" << endl
<< "> ";
cin >> T_initial;
cout << "Select desired number of Temperature Iterations:" << endl
<< "> ";
cin >> N_max;
cout << "Select desired number of step Iterations:" << endl
<< "> ";
cin >> N_step;
Initialize();
cout << "Write to file: (1 / 0) " << endl
<< "> ";
cin >> Write;
SA(Write);
system ("PAUSE");
return 0;
}
@strager - 我知道它的代码很糟糕,但不幸的是,由于我的项目所涉及的时间限制和随之而来的学习曲线,结果就是我们所需要的!:) 会在后期整理。
@ dirkgently - 这是这样做的最初原因,因此我的第一次尝试就是这样去做。