转载. 为方便理解, 在原博客的基础上加部分注释, 原博客地址:http://www.cnblogs.com/CsOH/p/6049117.html
今天终于用模拟退火过了一道题:CodeVS: P1344。
有 N ( <=20 ) 台 PC 放在机房内,现在要求由你选定一台 PC,用共 N-1 条网线从这台机器开始一台接一台地依次连接他们,最后接到哪个以及连接的顺序也是由你选定的,为了节省材料,网线都拉直。求最少需要一次性购买多长的网线。(说白了,就是找出 N 的一个排列 P1 P2 P3 ..PN 然后 P1 -> P2 -> P3 -> ... -> PN 找出 |P1P2|+|P2P3|+...+|PN-1PN| 长度的最小值)
这种问题被称为最优组合问题。传统的动态规划算法O(n22n)在n = 20的情况下空间、时间、精度都不能满足了。这时应该使用比较另类的算法。随机化算法在n比较小的最优化问题表现较好,我们尝试使用随机化算法。

#include<cstdio> #include<cstdlib> #include<ctime> #include<cmath> #include<algorithm> const int maxn = 21; double x[maxn], y[maxn]; double dist[maxn][maxn]; int path[maxn]; int n; double path_dist(){ double ans = 0; for(int i = 1; i < n; i++) { ans += dist[path[i - 1]][path[i]]; } return ans; } int main(){ srand(19260817U); // 使用确定的种子初始化随机函数是不错的选择 scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%lf%lf", x + i, y + i); for(int i = 0; i < n; i++) for(int j = i + 1; j < n; j++) dist[i][j] = dist[j][i] = hypot(x[i] - x[j], y[i] - y[j]); for(int i = 0; i < n; i++) path[i] = i; // 获取初始排列 double ans = path_dist(); // 初始答案 int T = 30000000 / n; // 单次计算的复杂度是O(n),这里的30000000是试出来的 while(T--){ std::random_shuffle(path, path + n); // 随机打乱排列 ans = std::min(ans, path_dist()); // 更新最小值 } printf("%.2lf", ans); }