/**
* Autor: Krzysztof Tatarynowicz
* Indeks: 221497
*
* Lista 1 - Travelling Salesman Problem
*
* 1. Założenia i działanie
*
* Algorytm służy do wyznaczania trasy dla komiwojażera.
* Program otrzymuje na standardowe wejście plik, który
* zawiera miasta wraz z ich współrzędnymi rzeczywistymi.
* Program zwraca na standardowe wyjście łączną długość
* trasy, wygenerowanej przez program. Na standardowe
* wyjście błędów program zwraca wierzchołki miast doce-
* lowych wraz z odległościami do nich, zgodnie ze sche-
* matem:
*
* x -> y (A.BCD...)
*
* gdzie x i y to etykiety miast, a A, B, C i D to cyfry
* tworzące liczbę rzeczywistą stanowiącą odległość
* między miastami x i y.
*
* 2. Realizacja
*
* 2. 1. Opis
*
* Algorytm działa na zasadzie wyboru najbliższego sąsiada,
* to jest miasta, które nie zostało jeszcze odwiedzone, a
* ma najkrótszą odległość doń.
*
* 2. 2. Lista TABU
*
* Listę TABU standardowo stanowią miasta, które zostały
* odwiedzone i nie powinno się ich więcej brać pod uwagę
* wyznaczając trasę. W programie lista TABU została
* zaimplementowana przez kopię listy miast. Z tej kopii
* kolejno usuwa się miasta, które zostały rozpatrzone i
* uwzględnione w trasie.
*
* 2. 3. Uproszczony schemat
*
* Algorytm tworzy listę miast ze współrzędnymi. Potem tworzy
* dwuwymiarową tablicę odległości między miastami (tablica
* jest rozmiaru N x N, gdzie N to liczba wszystkich miast).
* Następnie tworzy kopię listy miast i pracując na tej kopii
* w pętli:
*
* 1) jeśli to pierwsza iteracja, to ustawia wskaźnik na ostatnie
* rozpatrywane miasto jako pierwsze (etykieta '1') i kończy ten
* przebieg pętli (continue)
*
* 2) w kolejnej pętli znajduje miasto, do którego ma najbliżej
* (korzystając z dwuwymiarowej tablicy odległości), przy
* okazji zwiększa zmienną-akumulator o wartość tej odległości
*
* 3) po znalezieniu takiego miasta ustawia je jako ostatnio
* rozpatrywane
*
*/
// Includes
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stdio.h>
// City class
class City
{
public:
int label;
float x;
float y;
float distance;
bool visited;
std::vector<City> nbrs;
};
// Define namespace
using namespace std;
/**
* Globals and constants
*/
#define STARTING_LABEL 1 // label of city to start from
#define UNDEFINED 0 // undefined target city (auxiliary constant)
/**
* Sorting compare
*/
/**
* Method returning length of a randomized route
* @param cities Vector of cities to travel
* @param matrix Matrix of distances between cities
*/
float GetRandomRoute( vector <City> cities, vector <vector <float> > matrix )
{
// The length
float len = INFINITY;
// Copy of the cities vector
vector <City> copy = cities;
// Last city index considered
int last = -1;
// Label of last considered city
int lablast = -1;
// Ziarno losowości oparte na czasie
srand( time( NULL ) );
// Randomize the route
while( (int) copy.size() > 0 )
{
// Random number between [0, copy.size())
int rand = std::rand() % copy.size();
// If there's no last - it's the first iteration
if( last == -1 ) len = 0.0;
// Else get the distance between the last
// and the currently considered city
else
{
len += matrix.at( lablast - 1 ).at( copy.at( rand ).label - 1 );
cout << lablast << " -> " << copy.at( rand ).label << " (" << matrix.at( lablast - 1 ).at( copy.at( rand ).label - 1 ) << ")" << endl;
}
// Set last city as the currently considered
last = rand;
// Set the label of last conisdered city
lablast = copy.at( rand ).label;
// Remove that city from the copy vector
copy.erase( copy.begin() + rand );
}
// Include the travel from last considered city
// to the first one
len += matrix.at( last ).at( 0 );
// Return the length
return len;
}
/**
* Travelling Salesman function to find the shortest route
* @param cities Vector of cities to travel
* @param matrix Matrix of distances between cities
*/
float TravellingSalesman( vector <City> cities, vector <vector <float> > matrix )
{
// The shortest distance from city i to city j
float shortest;
float len = 0;
// Result vector of cities
vector <City> result;
// Get the matrix size
int size = matrix.size();
// Create vector of targets for each city
// Target is a city to travel from considered city
vector <int> target( size );
// Initialize the vector of targets
for( int i = 0; i < size; i++ )
{
target.at( i ) = UNDEFINED;
}
cities.at( 0 ).visited = true;
// Start from the STARTING_LABEL
int curr_id = STARTING_LABEL - 1;
int next_id = 0;
City curr = cities.at( curr_id );
// Fill the result vector
while( (int) result.size() < size )
{
// Insert current city to the results
result.push_back( curr );
// Initialize shortest distance
shortest = INFINITY;
// Find nearest neighbour
for( int i = 0; i < size; i++ )
{
// The same target as start
if( i == curr_id ) continue;
// Is already target of another city
if( cities.at( i ).visited == true ) continue;
// Get distance to the i-th city
float dist = matrix.at( curr_id ).at( i );
if( dist < shortest )
{
// If the current city had a target city
// then remove it
if( target.at( curr_id ) != UNDEFINED )
{
cities.at( target.at( curr_id ) ).visited = false;
target.at( curr_id ) = UNDEFINED;
}
// Found the nearest neighbour
shortest = dist;
target.at( curr_id ) = i;
next_id = i;
cities.at( i ).visited = true;
}
}
// Switch the currently considered city
curr_id = next_id;
curr = cities.at( curr_id );
}
// Also push the first city at the end of the result vector
// as it is the ending point of the travel
result.push_back( cities.at( STARTING_LABEL - 1 ) );
// Calculate total length
for( int i = 0; i < size; i++ )
{
int from = result.at( i ).label - 1;
int to = result.at( i + 1 ).label - 1;
len += matrix.at( from ).at( to );
// Console out the route
cerr << from + 1 << " -> " << to + 1 << " (" << matrix.at( from ).at( to ) << ")" << endl;
}
// cout << endl;
// Console out the total length
// cout << len << endl;
return len;
}
// Calculate euclidean distance
float GetEuclideanDistance( City a, City b )
{
float ax = a.x;
float ay = a.y;
float bx = b.x;
float by = b.y;
float dx = ax - bx;
float dy = ay - by;
return sqrt( (dx * dx) + (dy * dy) );
}
/**
* Main function
*/
int main( int argc, char **argv )
{
int city, count, size;
float x;
float y;
vector <City> cities;
// Get the first line from stdin
scanf( "%d", &count );
size = count;
// Create matrix [count] x [count]
vector <vector <float> > matrix( size );
// Save the cities with their coordinates
while( count-- )
{
City new_city;
scanf( "%d %f %f", &city, &x, &y );
new_city.label = city;
new_city.x = x;
new_city.y = y;
new_city.visited = false;
cities.push_back( new_city );
}
// Prepare the matrix
for( int i = 0; i < size; i++ )
{
vector <float> dists( size );
matrix.at( i ) = dists;
}
// Calculate distances between cities and save them into
// the matrix
for( int i = 0; i < size; i++ )
{
for( int j = 0; j < size; j++ )
{
if( i == j )
{
matrix.at( i ).at( j ) = 0.0;
continue;
}
City a, b;
a = cities.at( i );
b = cities.at( j );
float dist = GetEuclideanDistance( a, b );
matrix.at( i ).at( j ) = dist;
matrix.at( j ).at( i ) = dist;
}
}
// Run the travelling salesman
float regular = TravellingSalesman( cities, matrix );
/*
Random generating is worse idea...
cout << endl << "Random: " << endl;
float random1 = GetRandomRoute( cities, matrix );
*/
cout << regular << endl;
// Return from main
return 0;
}