I'm trying to solve this problem by bruteforce, but it seems to run very slow when given 7 (which is 2*7 points).
Note: I only need to run it to maximum 2*8 points
Problem statement:
Given 2*N points in a 2d plane, connect them in pairs to form N line segments. Minimize the total length of all the line segments.
Example:
Input: 5 10 10 20 10 5 5 1 1 120 3 6 6 50 60 3 24 6 9 0 0
Output: 118.4
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;
class point{
public:
double x, y;
};
double getLength(point a, point b){
return hypot((a.x - b.x), (a.y - b.y));
}
static double mini = INT_MAX;
void solve(vector <point> vec, double sum){
double prevSum = sum;
if(sum > mini){
return;
}
if(vec.size() == 2){
sum += getLength(vec[0], vec[1]);
mini = min(mini, sum);
return;
}
for(int i = 0; i < vec.size() - 1; i++){
for(int j = i + 1; j < vec.size(); j++){
sum = prevSum;
vector <point> temp = vec;
sum += getLength(temp[i], temp[j]);
temp.erase(temp.begin() + j);
temp.erase(temp.begin() + i);
solve(temp, sum);
}
}
}
int main(){
point temp;
int input;
double sum = 0;
cin >> input;
vector<point> vec;
for(int i = 0; i < 2 * input; i++){
cin >> temp.x >> temp.y;
vec.push_back(temp);
}
solve(vec, sum);
cout << fixed << setprecision(2) << mini << endl;
}
How can I speed up this code ?
I don't think this is what you are looking for but I mention it for completeness sake anyway. The problem can be formulated as a Mixed Integer Programming (MIP) problem.
We have distances:
d(i,j) = distance between point i and j (only needed for i<j)
and decision variables
x(i,j) = 1 if points i and j are connected (only needed for i<j)
0 otherwise
Then we can write:
Solving this problem can be done with widely available MIP solvers and leads to proven optimal solutions. A small example with 50 points:
You can solve this iteratively by using next_permutation() to go through all the permutations one by one. Apologies for the messy code, but this should show you how to do it:
struct Point {
Point(int x, int y) : x(x), y(y) {
}
bool operator< (const Point& rhs) {
const int key1 = y * 1000 + x;
const int key2 = rhs.y * 1000 + rhs.x;
return key1 < key2;
}
double dist(const Point& next) {
const double h = (double)(next.x - x);
const double v = (double)(next.y - y);
return sqrt(h*h + v*v);
}
int x, y;
};
You need the operator so you have some sort of sorting key for your points, so next_permutation can go through them in lexicographical increasing order. double getShortestDist(std::vector p) {
double min = 200000;
std::sort(p.begin(), p.end());
while(std::next_permutation(p.begin(), p.end())) {
double sum = 0.0;
for (int i = 0; i < p.size(); i+= 2) {
sum += p[i].dist(p[i+1]);
}
if (sum < min) {
min = sum;
}
}
return min;
}
int main(int argc, char*argv[]) {
static const int arr[] = {
10, 10, 20, 10, 5, 5, 1, 1, 120, 3, 6, 6, 50, 60, 3, 24, 6, 9, 0, 0
};
std::vector<Point> test;
for (int i = 0; i < 20; i += 2) {
test.push_back(Point(arr[i], arr[i+1]));
printf("%d %d\n", arr[i], arr[i+1]);
}
printf("Output: %d, %f", test.size(), getShortestDist(test));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With