我目前正在编写模拟退火代码来解决旅行商问题,并且在存储和使用来自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;
}
@dirkgently - 这是这样做的最初原因,因此我的第一次尝试就是这样做。
答案 0 :(得分:13)
这个怎么样? (KISS解决方案)
void LoadCities() {
int x, y;
ifstream in("Cities.txt");
if (!in) {
cout << "Cannot open file.\n";
return;
}
for (y = 0; y < 15; y++) {
for (x = 0; x < 15; x++) {
in >> distances[x][y];
}
}
in.close();
}
适合我。可能不是那么复杂,也许不是很高效,但只要你不读1000x1000数组,就不会有任何差别。
答案 1 :(得分:1)
它甚至可以编译吗?我得到了~7个错误。样本:
strtok(cities, "\n");
strtok()
的第一个参数是char *
而不是std :: string。
这有帮助吗?
void LoadCities()
{
std::vector<double> f((std::istream_iterator<double>
(std::ifstream("city.txt"))), /* replace filename with your own */
(std::istream_iterator<double>()));
if (!f.empty()) {
std::cout << f.size() << "\n";
/* print an arbitrary data point with 2 places of decimal */
std::cout << std::setprecision(2) << f[ 0 ] << std::endl;
}
}
使用矩阵并不意味着您需要拥有多维数组。特别是,使用2D阵列。当然,它更容易阅读和写作;)
答案 2 :(得分:1)
你可能想要更简单的东西,比如:
std::vector<std::vector<std::string> > LoadCities(const std::string &filename)
{
using namespace std;
ifstream file;
file.open(filename, ios::in | ios::out);
if(!file.is_open()) {
// error
return vector<vector<double> >();
}
vector<vector<double> > data;
string line;
while(!std::getline(file, line, '\n').eof()) {
istringstream reader(line);
vector<double> lineData;
string::const_iterator i = line.begin();
while(!reader.eof()) {
double val;
reader << val;
if(reader.fail())
break;
lineData.push_back(val);
}
data.push_back(lineData);
}
return data;
}
基本上您使用流来输入数据。我可能做错了(我从未处理过iostreams; P)但这应该会让你对如何构造矩阵读取器有一个大概的了解。
答案 3 :(得分:0)
以下是我加载/保存它的方法:
#include <iostream>
#include <fstream>
#include <string>
int width = 0;
int height = 0;
double **distances;
void WriteDouble( std::ofstream &stream, double toWrite )
{
char buffer[8];
memcpy( buffer, &toWrite, 8 );
stream.write( buffer, 8 );
}
void WriteInt( std::ofstream &stream, int toWrite )
{
char buffer[4];
memcpy( buffer, &toWrite, 4 );
stream.write( buffer, 4 );
}
double ReadDouble( std::ifstream &stream )
{
double d = 0;
stream.read( (char *)&d, 8 );
return d;
}
int ReadInt( std::ifstream &stream )
{
int i = 0;
stream.read( (char *)&i, 4 );
return i;
}
void Save()
{
std::ofstream stream( "cities", std::ios::out | std::ios::binary );
if( !stream.good() ) {
throw std::exception( "Error opening stream" );
}
WriteInt( stream, width );
WriteInt( stream, height );
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
WriteDouble( stream, distances[x][y] );
}
}
stream.close();
}
void Load()
{
std::ifstream stream( "cities", std::ios::in | std::ios::binary );
if( !stream.good() ) {
throw std::exception( "Error opening stream" );
}
width = ReadInt( stream );
height = ReadInt( stream );
distances = new double *[width];
for( int i = 0; i < width; i++ ) {
distances[i] = new double[height];
}
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
distances[x][y] = ReadDouble( stream );
}
}
stream.close();
}
void RunSaveTest()
{
width = 15;
height = 15;
distances = new double *[width];
for( int i = 0; i < width; i++ ) {
distances[i] = new double[height];
}
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
distances[x][y] = (double)x / (double)( y + 1 );
std::cout << distances[x][y] << std::endl;
}
}
Save();
}
void RunLoadTest()
{
Load();
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
std::cout << distances[x][y] << std::endl;
}
}
}
int main()
{
RunSaveTest();
// RunLoadTest();
return 0;
}
答案 4 :(得分:0)
我的博客参考:http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/
此代码段具有更高的容错能力,而不是假设所有内容都格式正确。
#include <istream>
#include <string>
#include <sstream>
#include <vector>
// load matrix from an ascii text file.
void load_matrix(std::istream* is,
std::vector< std::vector<double> >* matrix,
const std::string& delim = " \t")
{
using namespace std;
string line;
string strnum;
// clear first
matrix->clear();
// parse line by line
while (getline(*is, line))
{
matrix->push_back(vector<double>());
for (string::const_iterator i = line.begin(); i != line.end(); ++ i)
{
// If i is not a delim, then append it to strnum
if (delim.find(*i) == string::npos)
{
strnum += *i;
if (i + 1 != line.end()) // If it's the last char, do not continue
continue;
}
// if strnum is still empty, it means the previous char is also a
// delim (several delims appear together). Ignore this char.
if (strnum.empty())
continue;
// If we reach here, we got a number. Convert it to double.
double number;
istringstream(strnum) >> number;
matrix->back().push_back(number);
strnum.clear();
}
}
}
// example
#include <fstream>
#include <iostream>
int main()
{
using namespace std;
// read the file
std::ifstream is("input.txt");
// load the matrix
std::vector< std::vector<double> > matrix;
load_matrix(&is, &matrix);
// print out the matrix
cout << "The matrix is:" << endl;
for (std::vector< std::vector<double> >::const_iterator it = matrix.begin(); it != matrix.end(); ++ it)
{
for (std::vector<double>::const_iterator itit = it->begin(); itit != it->end(); ++ itit)
cout << *itit << '\t';
cout << endl;
}
return 0;
}