Browse Source

problem solved by genetic algorithm

Kajetan Johannes Hammerle 3 years ago
parent
commit
eca0c7a3dd
4 changed files with 215 additions and 3 deletions
  1. 164 3
      Main.cpp
  2. 49 0
      Reader.cpp
  3. 2 0
      Reader.h
  4. BIN
      map.png

+ 164 - 3
Main.cpp

@@ -1,14 +1,175 @@
+#include <algorithm>
+#include <chrono>
+#include <climits>
 #include <iostream>
 
 #include "Reader.h"
 
+int center;
+Reader r;
+
+struct Data {
+    std::vector<int> order;
+    std::vector<int> vehicles;
+    mutable int fitness = -1;
+
+    Data(int size) : order(size, 0), vehicles(size, rand() % 4) {
+        int counter = -1;
+        for(int& i : order) {
+            counter++;
+            if(counter == center) {
+                counter++;
+            }
+            i = counter;
+        }
+    }
+
+    int getFitness() const {
+        if(fitness != -1) {
+            return fitness;
+        }
+        int last[4] = {center, center, center, center};
+        int sum[4] = {0, 0, 0, 0};
+        fitness = 0;
+        for(size_t i = 0; i < order.size(); i++) {
+            int v = vehicles[i];
+            sum[v] += r[last[v]][order[i]];
+            last[v] = order[i];
+        }
+        for(int i = 0; i < 4; i++) {
+            sum[i] += r[last[i]][center];
+        }
+        int max = std::max(std::max(sum[0], sum[1]), std::max(sum[2], sum[3]));
+        fitness = sum[0] + sum[1] + sum[2] + sum[3] + max * 4;
+        return fitness;
+    }
+
+    void mutate() {
+        if(rand() & 1) {
+            vehicles[rand() % vehicles.size()] = rand() % 4;
+        } else {
+            int a = rand() % vehicles.size();
+            int b = rand() % vehicles.size();
+            if(b <= a) {
+                std::swap(a, b);
+            }
+            int oldB = order[b];
+            for(int i = b; i > a; i--) {
+                order[i] = order[i - 1];
+            }
+            order[a] = oldB;
+
+            oldB = vehicles[b];
+            for(int i = b; i > a; i--) {
+                vehicles[i] = vehicles[i - 1];
+            }
+            vehicles[a] = oldB;
+        }
+        fitness = -1;
+    }
+
+    void print() const {
+        for(int i : order) {
+            std::cout << i << " ";
+        }
+        std::cout << "| ";
+        for(int i : vehicles) {
+            std::cout << i << " ";
+        }
+        std::cout << "| " << getFitness() << "\n";
+    }
+
+    void prettyPrint() const {
+        for(int i = 0; i < 4; i++) {
+            std::cout << i << ": " << r.getName(center) << " -> ";
+            for(size_t k = 0; k < order.size(); k++) {
+                if(vehicles[k] == i) {
+                    std::cout << r.getName(order[k]) << " -> ";
+                }
+            }
+            std::cout << r.getName(center) << "\n";
+        }
+    }
+
+    bool operator<(const Data& other) const {
+        return getFitness() < other.getFitness();
+    }
+};
+
+std::vector<Data> population;
+
+static void init() {
+    for(int i = 0; i < 1000; i++) {
+        population.push_back(Data(r.getSize() - 1));
+    }
+    for(Data& data : population) {
+        for(int i = 0; i < 40; i++) {
+            data.mutate();
+        }
+    }
+}
+
+static void sort() {
+    std::sort(population.begin(), population.end());
+}
+
+static void findCenter() {
+    int min = INT_MAX;
+    int index = 0;
+    for(int i = 0; i < r.getSize(); i++) {
+        int sum = 0;
+        for(int k = 0; k < r.getSize(); k++) {
+            sum += r[i][k];
+        }
+        if(sum < min) {
+            index = i;
+            min = sum;
+        }
+    }
+    center = index;
+}
+
+long getNanos() {
+    return std::chrono::high_resolution_clock::now().time_since_epoch().count();
+}
+
 int main() {
-    Reader r;
+    long start = -getNanos();
+
     if(r.read("romaniaroads.pl")) {
         return 0;
     }
+    findCenter();
+
     r.print();
-    std::cout << "distance from " << r.getName(0) << " to " << r.getName(1)
-              << " is " << r[0][1] << "\n";
+
+    start += getNanos();
+
+    long loop = -getNanos();
+    init();
+    sort();
+
+    for(int gens = 0; gens < 250; gens++) {
+        size_t half = population.size() / 2;
+        for(size_t i = half; i < population.size(); i++) {
+            int parent = rand() % half;
+            population[i] = population[parent];
+            population[i].mutate();
+        }
+        sort();
+    }
+
+    for(size_t i = population.size(); i > 0; i--) {
+        population[i - 1].print();
+    }
+
+    population[0].prettyPrint();
+    std::cout << "center is " << r.getName(center) << "\n";
+
+    loop += getNanos();
+
+    std::cout << "Start: " << start / 1'000'000 << "ms\n";
+    std::cout << "Loop: " << loop / 1'000'000 << "ms\n";
+
     return 0;
 }

+ 49 - 0
Reader.cpp

@@ -1,3 +1,4 @@
+#include <climits>
 #include <fstream>
 #include <iostream>
 
@@ -11,6 +12,10 @@ const std::vector<int>& Reader::operator[](int x) const {
     return distances[x];
 }
 
+int Reader::getSize() const {
+    return ids;
+}
+
 int Reader::getOrAddId(const std::string& s) {
     auto found = nameToId.find(s);
     if(found != nameToId.end()) {
@@ -79,6 +84,9 @@ bool Reader::read(const char* path) {
         distances[fromId][toId] = distance;
         distances[toId][fromId] = distance;
     }
+    for(int i = 0; i < ids; i++) {
+        distance(i);
+    }
     return false;
 }
 
@@ -89,4 +97,45 @@ void Reader::print() const {
         }
         std::cout << "\n";
     }
+}
+
+struct Node {
+    int distance = INT_MAX;
+    bool visited = false;
+};
+
+static bool notAllVisited(const std::vector<Node>& nodes) {
+    for(const Node& n : nodes) {
+        if(!n.visited) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void Reader::distance(int column) {
+    std::vector<Node> nodes(ids, Node());
+    nodes[column].distance = 0;
+    while(notAllVisited(nodes)) {
+        size_t minIndex = 0;
+        int minDistance = INT_MAX;
+        for(size_t i = 0; i < nodes.size(); i++) {
+            if(!nodes[i].visited && nodes[i].distance < minDistance) {
+                minIndex = i;
+                minDistance = nodes[i].distance;
+            }
+        }
+        nodes[minIndex].visited = true;
+        for(int i = 0; i < ids; i++) {
+            if(!nodes[i].visited && distances[minIndex][i] != -1) {
+                int newDistance = minDistance + distances[minIndex][i];
+                if(newDistance < nodes[i].distance) {
+                    nodes[i].distance = newDistance;
+                }
+            }
+        }
+    }
+    for(size_t i = 0; i < nodes.size(); i++) {
+        distances[column][i] = nodes[i].distance;
+    }
 }

+ 2 - 0
Reader.h

@@ -16,10 +16,12 @@ public:
     void print() const;
     const std::string& getName(int id);
     const std::vector<int>& operator[](int x) const;
+    int getSize() const;
 
 private:
     int getOrAddId(const std::string& s);
     std::string trim(const std::string& s) const;
+    void distance(int column);
 };
 
 #endif

BIN
map.png