⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 travel.h

📁 The source code of Travelling Salesman Problem. Implement in Visual C++.
💻 H
字号:
/*
 Copyright (c) 2001 
 Author: Konstantin Boukreev 
 E-mail: konstantin@mail.primorye.ru 

 Created: 07.09.2001 17:14:06
 Version: 1.0.0

 Genome for Travelling Salesman Problem 
  
*/

#ifndef _Travel_e3dfe72a_06ea_439d_9d40_08de1bb784a2
#define _Travel_e3dfe72a_06ea_439d_9d40_08de1bb784a2

#if _MSC_VER > 1000 
#pragma once
#endif // _MSC_VER > 1000

#include "MemTools.h"

/////////////////////////////////////////////////

struct TSPData
{
	struct point
	{
		point(int x = 0, int y = 0) {this->x = x; this->y = y;}
		int x; int y;
	};

	typedef std::vector<point> points;
	typedef std::vector<unsigned> cache;

	mem_pool	m_mem_pool;
	points		m_points;		
//	unsigned	m_size;			// number of points
	cache		m_cache;		// auxiliary member for corssover
	unsigned*	m_map;			// auxiliary member for corssover
	float*		m_routes;		// pre-computed cost of routes

	TSPData() 
	{
	//	m_size = 0;
		m_map  = 0;
		m_routes = 0;
	}

	/*
	TSPData(unsigned size) 
		: // m_size(size), 
		m_routes(0)
	{
		m_points.resize(size);		
		m_cache.resize(size);
		m_map = alloc_travel();
	}
	*/
	
	TSPData(const TSPData& p)
		: // m_size(p.m_size), 
		m_routes(0)
	{
		m_points.assign(p.m_points.begin(), p.m_points.end());
		m_cache.resize(size());
		m_map = alloc_travel();

		m_routes = new float [size() * size()];
		memcpy(m_routes, p.m_routes, size() * size() * sizeof (float));
	}

	~TSPData()
	{
		free_travel(m_map);
		delete [] m_routes;
	}

	void init(unsigned reserved = 0)
	{		
		m_points.clear();
		m_cache.clear();
		free_travel(m_map);
		m_map = 0;
	//	m_size = 0;
		delete [] m_routes;
		m_routes = 0;

		if (reserved > 0)
			m_points.reserve(reserved);
	}
	
	void add(int x, int y)
	{
		m_points.push_back(point(x, y));
	//	m_size++;
	}
	
	void end()
	{
		m_mem_pool.cleanup();
	//	m_size = m_points.size();
		m_cache.resize(size());
		m_map = alloc_travel();

		delete [] m_routes;
		m_routes = new float [size() * size()];

		for (unsigned iy = 0; iy < size(); ++iy)
			for (unsigned ix = 0; ix < size(); ++ix)
				m_routes[ix + iy * size()] = (float)cost(m_points[ix], m_points[iy]); 
	}

	unsigned size() const {return m_points.size();}

	static double cost(point& pt1, point& pt2) 
	{
		int x = abs(pt1.x - pt2.x);
		int y = abs(pt1.y - pt2.y);
		if (!x) return y;
		if (!y) return x;
		return sqrt(x*x + y*y);
	}

	double cost(unsigned p1, unsigned p2)
	{
		return m_routes[p1 + (p2 * size())];
	}

	double cost(unsigned* begin, unsigned* end) 
	{
		double value = 0;
		
		unsigned* p1 = begin;
		unsigned* p2 = begin + 1;
				
		for (; p2 != end; p2++)
		{		
			value += m_routes[*p1 + ((*p2) * size())];
			p1 = p2;
		}
	
		value += m_routes[*p1 + ((*begin) * size())];
		return value;
	}

	unsigned* alloc_travel ()
	{	
		return (unsigned*)m_mem_pool.allocate(size() * sizeof(unsigned));
	}
	
	void free_travel (unsigned* p)
	{		
		m_mem_pool.deallocate(p);
	}		
};

// lightweigth memory optimization

struct TSPBase
{
	/*
	static mem_pool g_mem_pool;
	
	void* operator new (size_t s)
	{ return g_mem_pool.allocate(s); }
	
	void operator delete (void* p)
	{ g_mem_pool.deallocate(p);	}
	*/

	static __declspec( thread ) mem_pool* g_mem_pool;
	
	void* operator new (size_t s)
	{ return g_mem_pool->allocate(s); }
	
	void operator delete (void* p)
	{ g_mem_pool->deallocate(p);	}
};

template <typename R>
struct TSPGene  : TSPBase
{
	typedef float Fitness;
	typedef R Random;
	typedef TSPData Context;
	
	Context*	m_ctx;
	unsigned*	m_travel;
	Fitness		m_fitness;
	Random&		m_random;

	TSPGene(Context* ctx, Random& r)
		: m_random(r), m_ctx(ctx)
	{		
		m_travel = m_ctx->alloc_travel();

		for (unsigned i = 0; i < m_ctx->size(); i++)
			m_travel[i] = i;	

		std::random_shuffle(m_travel, m_travel + m_ctx->size(), m_random);
	}

	TSPGene(const TSPGene& gn)
		: m_random(gn.m_random), m_travel(0)
	{ this->operator = (gn); }

	TSPGene(const TSPGene& gn, Context* ctx, Random& r)
		: m_random(r), m_ctx(ctx)		
	{ 
		m_travel = m_ctx->alloc_travel();
		m_fitness = gn.m_fitness;
		memcpy(m_travel, gn.m_travel, m_ctx->size() * sizeof(unsigned));								
	}

	// crossover
	TSPGene(const TSPGene& parent1, const TSPGene& parent2)
		: m_random(parent1.m_random), m_ctx(parent1.m_ctx)
	{
		const unsigned BUSY = 0xffffffff;

		m_travel = m_ctx->alloc_travel();
		memset(m_ctx->m_map, 0, m_ctx->size() * sizeof (unsigned));
			
		TSPData::cache::iterator pch = m_ctx->m_cache.begin();		
		unsigned* p		= m_travel;
		unsigned* p1	= parent1.m_travel;
		unsigned* p2	= parent2.m_travel;

		///////////////////////////////////////////
		// Greedy Crossover by Grefenstette
		
		*p = m_random.flip() ? *p1 : *p2;
		m_ctx->m_map[*p] = BUSY;

		while(p < m_travel + m_ctx->size() - 1)
		{
			unsigned v  = *p++;

			for (p1	= parent1.m_travel; p1 < parent1.m_travel + m_ctx->size(); ++p1)
				if (v == *p1) break;
			_ASSERTE(p1 < parent1.m_travel + m_ctx->size());

			for (p2	= parent2.m_travel; p2 < parent2.m_travel + m_ctx->size(); ++p2)
				if (v == *p2) break;
			_ASSERTE(p2 < parent2.m_travel + m_ctx->size());
			
			unsigned v1 = p1 == parent1.m_travel + m_ctx->size() - 1 ? *parent1.m_travel : *(++p1);
			unsigned v2 = p2 == parent2.m_travel + m_ctx->size() - 1 ? *parent2.m_travel : *(++p2);

			if (m_ctx->m_map[v1]) v1 = BUSY;		// already busy				
			if (m_ctx->m_map[v2]) v2 = BUSY;		// already busy

			if (v1 != BUSY && v2 != BUSY)
			{
				_ASSERTE(pch != m_ctx->m_cache.end());

				if (v1 == v2)
				{
					*p = v1;
				}
				else
				{
					double c1 = m_ctx->cost(v, v1);
					double c2 = m_ctx->cost(v, v2);			
					bool b	= c1 < c2;
					*p		= b ? v1 : v2;
					*pch++	= b ? v2 : v1;		// copy to a cache a unused point
				}				
			}
			else if (v1 == BUSY && v2 != BUSY)
				*p = v2;
			else if (v1 != BUSY && v2 == BUSY)
				*p = v1;
			else
			{	
				// todo : random select from cache ?

				_ASSERTE(pch != m_ctx->m_cache.begin());
				do {pch--;
				} while (m_ctx->m_map[*pch]);	// search a first unused point into a cache 
												// there is always an unused point into a cache
				*p = *pch;						// copy from the cache
			}

			m_ctx->m_map[*p] = BUSY;	// mark as busy			
		}
				
		#ifdef _DEBUG
		// checks a validity of travel
		memset(m_ctx->m_map, 0, m_ctx->size() * sizeof (unsigned));
		unsigned value1 = 0, value2 = 0;
		{for (unsigned i = 0; i < m_ctx->size(); i++)
		{
			value1 += m_travel[i];
			value2 += i;
			_ASSERTE(m_ctx->m_map[m_travel[i]] != BUSY);
			m_ctx->m_map[m_travel[i]] = BUSY;
		}}
		_ASSERTE(value1 == value2);
		#endif
	}

	~TSPGene()
	{
		m_ctx->free_travel(m_travel);
	}

	TSPGene& operator = (const TSPGene& gn)
	{ 
		if (this != &gn)
		{	
			m_ctx->free_travel(m_travel);
			m_ctx = gn.m_ctx;
			m_travel = m_ctx->alloc_travel()			
			m_fitness = gn.m_fitness;
			memcpy(m_travel, gn.m_travel, m_ctx->size() * sizeof(unsigned));			
		}
		return *this; 
	}

	bool operator == (const TSPGene& gn) const
	{ 
		if (this != &gn)
		{
			return memcmp(m_travel, gn.m_travel, m_ctx->size() * sizeof(unsigned)) == 0;
		}		
		return true; 
	}

	bool operator != (const  TSPGene& gn) const
	{ 	return ! this->operator == (gn); }

	bool operator < (const TSPGene& gn) const
	{
		if (this == &gn) return false;
		return fitness() < gn.fitness();
	}

	friend 
	std::ostream& operator << (std::ostream& os, TSPGene& gn);

	void mutation() 
	{
		if (m_random.hazard(20, 100))		
		{
			// random mutation

			unsigned x1 = m_random.roll(m_ctx->size());		
			unsigned x2 = m_random.roll(m_ctx->size());
			if (x1 != x2)
			{		
				std::swap(m_travel[x1], m_travel[x2]);
				return;
			}			
		}
		else
		{	
			// Greedy-Swap Mutation

			update();
			Fitness f = fitness();
						
			for (unsigned i = 0; i < m_ctx->size(); i++)
			{				
				unsigned x1 = m_random.roll(m_ctx->size());
				unsigned x2 = m_random.roll(m_ctx->size());
				if (x1 != x2)
				{		
					std::swap(m_travel[x1], m_travel[x2]);
					update();
					if (f > fitness())
						return;
					// restore back
					std::swap(m_travel[x2], m_travel[x1]);
				}	
			}
		}		
	}

	void heuristics_2opt()
	{
		// 2opt mutation by Hiroaki Sengoku and Ikuo YOSHIHARA
		
		update();
		Fitness f = fitness();
		
		for (unsigned x1 = 0; x1 < m_ctx->size() - 1; ++x1)
		{						
			for (unsigned i = x1 + 1; i < m_ctx->size(); ++i)		
			{	
				std::swap(m_travel[x1], m_travel[i]);
				// check fitness
				update();
				if (f > fitness())				
					f = fitness();
				else
					// restore back
					std::swap(m_travel[i], m_travel[x1]);
			} 			
		}		
	}

	bool update() 
	{
		m_fitness = (float) m_ctx->cost(m_travel, m_travel + m_ctx->size());
		return false; // the optimum is never known
	}

	Fitness fitness() const				 {return m_fitness;}
};

template <typename R>
std::ostream& operator << (std::ostream& os, TSPGene<R>& gn)
{	
	os << "fitness (" << gn.m_fitness << ") "
	   << "travel <";
	for (unsigned* p = gn.m_travel; p < gn.m_travel + gn.m_ctx->size(); p++)
		os << *p << " ";
	os << "> ";
	return os;
}

#endif //_Travel_e3dfe72a_06ea_439d_9d40_08de1bb784a2

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -