Advertisement
Guest User

Untitled

a guest
May 19th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.42 KB | None | 0 0
  1. /*Найдите приближенное решение метрической неориентированной задачи коммивояжера
  2. в полном графе (на плоскости) с помощью минимального остовного дерева,
  3. построенного в первой задаче. Оцените качество приближения на случайном наборе
  4. точек, нормально распределенном на плоскости с дисперсией 1. Нормально
  5. распределенный набор точек получайте с помощью std::normal_distribution. При
  6. фиксированном N, количестве вершин графа, несколько раз запустите оценку
  7. качества приближения. Вычислите среднее значение и среднеквадратичное отклонение
  8. качества приближения для данного N. Запустите данный эксперимент для всех N в
  9. некотором диапазоне, например, [2, 10]. Автоматизируйте запуск экспериментов. В
  10. решении требуется разумно разделить код на файлы. Каждому классу - свой
  11. заголовочный файл и файл с реализацией.
  12. */
  13.  
  14. #include "Graph.h"
  15. #include <math.h>
  16. #include <iostream>
  17. #include <limits>
  18. #include <memory>
  19. #include <optional>
  20. #include <random>
  21. #include <set>
  22. #include <stack>
  23. #include <vector>
  24.  
  25. using IntPair = std::pair<int, int>;
  26. using IntVector = std::vector<int>;
  27.  
  28. bool operator<(Edge edge1, Edge edge2) {
  29. auto edge1_pair = std::make_pair(edge1.vertex1_, edge1.vertex2_);
  30. auto edge2_pair = std::make_pair(edge2.vertex1_, edge2.vertex2_);
  31. return edge1_pair < edge2_pair;
  32. }
  33.  
  34. Graph::Graph(int vertex_count)
  35. : adjacency_matrix_(vertex_count, std::vector<double>(vertex_count, 0)) {}
  36.  
  37. void Graph::AddEdge(int vertex1, int vertex2, double weight) {
  38. adjacency_matrix_[vertex1][vertex2] = weight;
  39. adjacency_matrix_[vertex2][vertex1] = weight;
  40. edges_.emplace(vertex1, vertex2, weight);
  41. edges_.emplace(vertex2, vertex1, weight);
  42. }
  43.  
  44. int Graph::GetVertexCount() const { return adjacency_matrix_.size(); }
  45.  
  46. void Graph::FindComponentVertices(std::vector<int>& component_indexes,
  47. int component_representative,
  48. std::vector<bool>& is_visited,
  49. int component_index) const {
  50. component_indexes[component_representative] = component_index;
  51. is_visited[component_representative] = true;
  52. for (int vertex = 0; vertex < GetVertexCount(); ++vertex) {
  53. if (!is_visited[vertex] &&
  54. adjacency_matrix_[component_representative][vertex] > 0) {
  55. FindComponentVertices(component_indexes, vertex, is_visited,
  56. component_index);
  57. }
  58. }
  59. }
  60.  
  61. Graph Graph::GetForest() const {
  62. auto forest = std::make_shared<Graph>(GetVertexCount());
  63. return *forest;
  64. }
  65.  
  66. inline bool Graph::IsUpdateNeeded(
  67. int vertex1_component_index,
  68. const std::vector<std::optional<IntPair>>& new_edges,
  69. double new_weight) const {
  70. return !new_edges[vertex1_component_index].has_value() ||
  71. adjacency_matrix_[new_edges[vertex1_component_index].value().first]
  72. [new_edges[vertex1_component_index].value().second] >
  73. new_weight;
  74. }
  75.  
  76. inline bool Graph::IsAddedEdge(const std::set<IntPair>& added_edges,
  77. const std::optional<IntPair> new_edge) const {
  78. return added_edges.find(new_edge.value()) == added_edges.end();
  79. }
  80.  
  81. void Graph::AddNewEdgesToForest(
  82. Graph& forest, int& added_edge_count, std::set<IntPair>& added_edges,
  83. const std::vector<std::optional<IntPair>>& new_edges,
  84. double& minimal_spanning_tree_weight) const {
  85. for (auto&& new_edge : new_edges) {
  86. if (added_edge_count == GetVertexCount() - 1) {
  87. break;
  88. }
  89. if (IsAddedEdge(added_edges, new_edge)) {
  90. minimal_spanning_tree_weight +=
  91. adjacency_matrix_[new_edge.value().first][new_edge.value().second];
  92. added_edge_count++;
  93. forest.AddEdge(
  94. new_edge.value().first, new_edge.value().second,
  95. adjacency_matrix_[new_edge.value().first][new_edge.value().second]);
  96. added_edges.emplace(new_edge.value());
  97. added_edges.emplace(new_edge.value().second, new_edge.value().first);
  98. }
  99. }
  100. }
  101.  
  102. Graph Graph::GetMinimalSpanningTree() {
  103. std::set<IntPair> added_edges;
  104. double minimal_spanning_tree_weight = 0;
  105. auto forest = GetForest();
  106. int added_edge_count = 0;
  107.  
  108. while (added_edge_count < GetVertexCount() - 1) {
  109. std::vector<int> component_indexes(GetVertexCount());
  110. std::vector<std::optional<IntPair>> new_edges(GetVertexCount() -
  111. added_edge_count);
  112. int component_index = 0;
  113. std::vector<bool> is_visited(GetVertexCount(), false);
  114.  
  115. for (int vertex = 0; vertex < GetVertexCount(); ++vertex) {
  116. if (!is_visited[vertex]) {
  117. forest.FindComponentVertices(component_indexes, vertex, is_visited,
  118. component_index);
  119. component_index++;
  120. }
  121. }
  122. for (int vertex1 = 0; vertex1 < GetVertexCount(); ++vertex1) {
  123. for (int vertex2 = 0; vertex2 < adjacency_matrix_[vertex1].size();
  124. ++vertex2) {
  125. if (component_indexes[vertex1] != component_indexes[vertex2]) {
  126. int vertex1_component_index = component_indexes[vertex1];
  127. if (IsUpdateNeeded(vertex1_component_index, new_edges,
  128. adjacency_matrix_[vertex1][vertex2])) {
  129. new_edges[vertex1_component_index].emplace(vertex1, vertex2);
  130. }
  131. }
  132. }
  133. }
  134. AddNewEdgesToForest(forest, added_edge_count, added_edges, new_edges,
  135. minimal_spanning_tree_weight);
  136. }
  137. return forest;
  138. }
  139.  
  140. std::vector<int> Graph::GetEylerianCycle() {
  141. std::set<Edge> erased_edges;
  142. std::vector<int> eylerian_cycle;
  143. std::stack<int> added_vertices;
  144. added_vertices.emplace(0);
  145.  
  146. while (!added_vertices.empty()) {
  147. auto current_vertex = added_vertices.top();
  148. for (auto&& edge : edges_) {
  149. if (edge.vertex1_ == current_vertex) {
  150. added_vertices.emplace(edge.vertex2_);
  151. if (erased_edges.find(edge) == erased_edges.end()) {
  152. erased_edges.emplace(edge);
  153. erased_edges.emplace(edge.vertex2_, edge.vertex1_, edge.weight_);
  154. break;
  155. }
  156. edges_.erase(edge);
  157. auto edge_copy =
  158. std::make_shared<Edge>(edge.vertex2_, edge.vertex1_, edge.weight_);
  159. edges_.erase(*edge_copy);
  160. break;
  161. }
  162. }
  163. if (current_vertex == added_vertices.top()) {
  164. added_vertices.pop();
  165. eylerian_cycle.emplace_back(current_vertex);
  166. }
  167. }
  168. return eylerian_cycle;
  169. }
  170.  
  171. double Graph::GetApproximateCycleWeight(IntVector eylerian_cycle) const {
  172. double tour_cost = 0;
  173. int prev_vertex = eylerian_cycle[0];
  174. std::vector<bool> is_visited(GetVertexCount(), false);
  175. is_visited[eylerian_cycle[0]] = true;
  176. for (auto&& vertex : eylerian_cycle) {
  177. if (!is_visited[vertex]) {
  178. is_visited[vertex] = true;
  179. tour_cost += adjacency_matrix_[prev_vertex][vertex];
  180. prev_vertex = vertex;
  181. }
  182. }
  183. tour_cost += adjacency_matrix_[prev_vertex][eylerian_cycle[0]];
  184. return tour_cost;
  185. }
  186.  
  187. int GetTwoPower(int power) {
  188. int two_in_power = 1;
  189. for (int i = 0; i < power; ++i) {
  190. two_in_power *= 2;
  191. }
  192. return two_in_power;
  193. }
  194.  
  195. int GetBit(int bit_index, int mask) {
  196. for (int i = 0; i < bit_index; ++i) {
  197. mask /= 2;
  198. }
  199. return mask % 2;
  200. }
  201.  
  202. double Graph::GetGamiltonicPathWeight(
  203. int mask, int to,
  204. std::vector<std::vector<std::optional<double>>>& gamiltonic_path_weights)
  205. const {
  206. double gamilton_path_weight = std::numeric_limits<double>::max();
  207. if (mask == 1 && to == 0) {
  208. return 0;
  209. }
  210. if (GetBit(0, mask) == 1 && GetBit(to, mask) == 1 && to > 0) {
  211. for (int vertex = 0; vertex < GetVertexCount(); ++vertex) {
  212. if (adjacency_matrix_[to][vertex] > 0) {
  213. if (GetBit(vertex, mask) == 1) {
  214. if (!gamiltonic_path_weights[mask ^ GetTwoPower(to)][vertex]
  215. .has_value()) {
  216. gamiltonic_path_weights[mask ^ GetTwoPower(to)][vertex].emplace(
  217. GetGamiltonicPathWeight(mask ^ GetTwoPower(to), vertex,
  218. gamiltonic_path_weights));
  219. }
  220. if (gamiltonic_path_weights[mask ^ GetTwoPower(to)][vertex].value() +
  221. adjacency_matrix_[to][vertex] <
  222. gamilton_path_weight) {
  223. gamilton_path_weight =
  224. gamiltonic_path_weights[mask ^ GetTwoPower(to)][vertex]
  225. .value() +
  226. adjacency_matrix_[to][vertex];
  227. }
  228. }
  229. }
  230. }
  231. return gamilton_path_weight;
  232. }
  233. return std::numeric_limits<double>::max();
  234. }
  235.  
  236. double Graph::GetGamiltonicCycleWeight() const {
  237. std::vector<std::vector<std::optional<double>>> gamiltonic_way_weights(
  238. GetTwoPower(GetVertexCount()),
  239. std::vector<std::optional<double>>(GetVertexCount()));
  240. double gamiltonic_cycle_weight = std::numeric_limits<double>::max();
  241.  
  242. for (int vertex = 1; vertex < GetVertexCount(); ++vertex) {
  243. if (adjacency_matrix_[0][vertex] > 0) {
  244. if (!gamiltonic_way_weights[GetTwoPower(GetVertexCount()) - 1][vertex]
  245. .has_value()) {
  246. gamiltonic_way_weights[GetTwoPower(GetVertexCount()) - 1][vertex]
  247. .emplace(GetGamiltonicPathWeight(GetTwoPower(GetVertexCount()) - 1,
  248. vertex, gamiltonic_way_weights));
  249. }
  250. if (gamiltonic_way_weights[GetTwoPower(GetVertexCount()) - 1][vertex]
  251. .value() +
  252. adjacency_matrix_[0][vertex] <
  253. gamiltonic_cycle_weight) {
  254. gamiltonic_cycle_weight =
  255. gamiltonic_way_weights[GetTwoPower(GetVertexCount()) - 1][vertex]
  256. .value() +
  257. adjacency_matrix_[0][vertex];
  258. }
  259. }
  260. }
  261. return gamiltonic_cycle_weight;
  262. }
  263.  
  264. double GetStandardDeviation(double average_value,
  265. const std::vector<double>& values) {
  266. double standard_deviation = 0;
  267. for (auto&& value : values) {
  268. standard_deviation +=
  269. (average_value - value) * (average_value - value) / (values.size());
  270. }
  271. return sqrt(standard_deviation);
  272. }
  273.  
  274. void CarryOutExperiment() {
  275. const int experiment_count = 10;
  276. const int maximal_point_count = 10;
  277. std::default_random_engine generator;
  278. std::normal_distribution<double> distributor{0, 1};
  279. for (int i = 2; i < maximal_point_count + 1; ++i) {
  280. double coefficient_sum = 0;
  281. std::vector<double> experiment_results(experiment_count);
  282. for (int j = 0; j < experiment_count; ++j) {
  283. Graph graph = Graph(i);
  284. std::vector<std::pair<double, double>> points;
  285. points.reserve(i);
  286. for (int point_index = 0; point_index < i; ++point_index) {
  287. double x = distributor(generator);
  288. double y = distributor(generator);
  289. points.emplace_back(x, y);
  290. for (int k = 0; k < points.size(); ++k) {
  291. double distance =
  292. sqrt((x - points[k].first) * (x - points[k].first) +
  293. (y - points[k].second) * (y - points[k].second));
  294. graph.AddEdge(k, point_index, distance);
  295. }
  296. }
  297. Graph minimal_spanning_tree = graph.GetMinimalSpanningTree();
  298. IntVector eylerian_cycle = minimal_spanning_tree.GetEylerianCycle();
  299. double approximate_cycle_weight =
  300. graph.GetApproximateCycleWeight(eylerian_cycle);
  301. double gamiltonic_cycle_weight = graph.GetGamiltonicCycleWeight();
  302. coefficient_sum += approximate_cycle_weight / gamiltonic_cycle_weight;
  303. experiment_results[j] =
  304. approximate_cycle_weight / gamiltonic_cycle_weight;
  305. }
  306. std::cout << "Average approximation coefficient is "
  307. << coefficient_sum / experiment_count << std::endl;
  308. std::cout << "Standard deviation is "
  309. << GetStandardDeviation(coefficient_sum / experiment_count,
  310. experiment_results)
  311. << std::endl;
  312. }
  313. }
  314.  
  315. int main() {
  316. CarryOutExperiment();
  317. return 0;
  318. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement