2009-02-21 77 views
6

我目前正在编写一个模拟退火代码来解决旅行商问题,并遇到了存储和使用从txt文件中读取数据的困难。文件中的每一行&列表示各城市,存储为15×15矩阵的两个不同城市之间的距离:阅读矩阵txt文件并存储为数组

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()的细节。这不是干净,高效,整洁,并不是要在这个阶段,只需要工作的时刻。该版本(如下)可用于解决多项式问题(最简单的问题)。有什么需要做的将其转换为一个旅行商问题是:

  1. 写LoadCities()函数来收集距离数据。 (电流)

  2. 更改初始化()来获得距离的总参与

  3. 变化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 - 我知道它不好的代码,但不幸的是与参与我的项目的时间限制和consiquental学习曲线,结果是需要什么样的! :)它将在后期整理。

@ dirkgently - 这是这样做的最初原因,因此我的第一次尝试就是这样去做。

+0

关于实际问题的更多细节可能会有所帮助。你已经提供了很好的代码和很多细节,但是大多数都没有注明你真正想要解决的问题..... – SoapBox 2009-02-21 13:32:39

+0

这不是很好的代码......它甚至不应该编译!有一些问题。距离是双[15] [15],但是像指针一样分配。检查文件是否在任何操作完成之前打开。他将整个文件读入缓冲区......等等。 – strager 2009-02-21 13:36:17

+0

@strager:在缓冲区中读取整个文件是一种优化技术。很多我认识的人在编写编程竞赛代码时使用它;) – dirkgently 2009-02-21 13:44:02

回答

11

这个怎么样?(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

它甚至编译?我得到〜7个错误。样品:

strtok(cities, "\n");

strtok()第一个参数是一个char *,而不是一个std ::字符串。

这有帮助吗?

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数组。当然它更容易读写;)

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),但是这应该给你关于如何构造矩阵读取器的一般想法。

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; 
} 
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; 
}