C++ 旅行商问题的编译器优化
我正在研究旅行推销员问题,并正在研究以下版本: 城镇是二维空间中的点,从每个城镇到所有其他城镇都有路径,长度是点之间的距离。因此,很容易实现简单的解决方案,即检查n个点的所有排列并计算路径长度 然而,我发现,对于n>=10,编译器执行了一些魔术,并打印出一个肯定不是实际最短路径的值。我使用MicrosoftVisualStudio编译器以默认设置的发布模式进行编译。对于值10,30,它会思考30秒,然后返回一些看起来可能是正确的数字,但不是我用不同的方法检查的。对于n>40,它会立即计算结果,并且始终为2.14748e+09 我想解释一下编译器在不同的情况下会做什么10,30的情况非常有趣。还有一个例子,在这个例子中,这些优化比仅仅旋转到世界末日的程序更有用C++ 旅行商问题的编译器优化,c++,compiler-optimization,C++,Compiler Optimization,我正在研究旅行推销员问题,并正在研究以下版本: 城镇是二维空间中的点,从每个城镇到所有其他城镇都有路径,长度是点之间的距离。因此,很容易实现简单的解决方案,即检查n个点的所有排列并计算路径长度 然而,我发现,对于n>=10,编译器执行了一些魔术,并打印出一个肯定不是实际最短路径的值。我使用MicrosoftVisualStudio编译器以默认设置的发布模式进行编译。对于值10,30,它会思考30秒,然后返回一些看起来可能是正确的数字,但不是我用不同的方法检查的。对于n>40,它会立即计算结果,并
vector<pair<int,int>> points;
void min_len()
{
// n is a global variable with the number of points(towns)
double min = INT_MAX;
// there are n! permutations of n elements
for (auto j = 0; j < factorial(n); ++j)
{
double sum = 0;
for (auto i = 0; i < n - 1; ++i)
{
sum += distance_points(points[i], points[i + 1]);
}
if (sum < min)
{
min = sum;
s_path = points;
}
next_permutation(points.begin(), points.end());
}
for (auto i = 0; i < n; ++i)
{
cout << s_path[i].first << " " << s_path[i].second << endl;
}
cout << min << endl;
}
unsigned int factorial(unsigned int n)
{
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i;
return res;
}
你的阶乘函数溢出了。尝试将其替换为一个返回int64_t的代码,并看到您的代码需要3年时间才能在n>20时终止
constexpr uint64_t factorial(unsigned int n) {
return n ? n * factorial(n-1) : 1;
}
而且,你根本不需要计算这个。当所有排列都从排序位置开始时,std::next_排列函数返回0。您的阶乘函数溢出。尝试将其替换为一个返回int64_t的代码,并看到您的代码需要3年时间才能在n>20时终止
constexpr uint64_t factorial(unsigned int n) {
return n ? n * factorial(n-1) : 1;
}
而且,你根本不需要计算这个。当所有排列都从排序位置开始时,std::next_permutation函数返回0。factorialn的实现是什么?它可能已经溢出了。你为什么还要用阶乘呢?您应该只查看中的返回值,而不是责怪那些在定义行为时不允许返回错误结果的优化,您应该尝试一些调试。对于初学者,在每次迭代结束时跟踪min的值。确保next_permutation执行您认为它应该执行的操作-可能执行,但这属于调试时要验证的标准事项。额外积分:请注意,2.14748e+09很可能是INT_MAX的值@JaMiT我知道这要看情况而定,但我应该期望在30分钟内得到8分!置换?你对factorialn的实现是什么?它可能已经溢出了。你为什么还要用阶乘呢?您应该只查看中的返回值,而不是责怪那些在定义行为时不允许返回错误结果的优化,您应该尝试一些调试。对于初学者,在每次迭代结束时跟踪min的值。确保next_permutation执行您认为它应该执行的操作-可能执行,但这属于调试时要验证的标准事项。额外积分:请注意,2.14748e+09很可能是INT_MAX的值@JaMiT我知道这要看情况而定,但我应该期望在30分钟内得到8分!排列?