乱搞算法
爬山算法
对于单峰函数可行
实现:
先随机一个答案,之后每次将其与与其在一定范围内相邻的答案选举一个最优解,每一次运算后范围逐渐缩小,直到范围小于阈值
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int N = 20; int n; double dis[N], cans[N], f[N][N], ans[N]; inline void solve() { double res = 0; for (int i = 1; i <= n + 1; i++) { dis[i] = 0; cans[i] = 0; for (int j = 1; j <= n; j++) dis[i] += pow(f[i][j] - ans[j], 2); dis[i] = sqrt(dis[i]); res += dis[i]; } res /= n + 1; for (int i = 1; i <= n + 1; i++) { for (int j = 1; j <= n; j++) { cans[j] += (dis[i] - res) * (f[i][j] - ans[j]) / res; } } } int main() { scanf("%d", &n); for (int i = 1; i <= n + 1; i++) { for (int j = 1; j <= n; j++) { scanf("%lf", &f[i][j]); ans[j] += f[i][j]; } } for (int i = 1; i <= n; i++) ans[i] /= (n + 1); for (double t = 10001; t >= 0.0001; t *= 0.99995)//每次缩小范围(降温) { solve(); for (int i = 1; i <= n; i++) ans[i] += cans[i] * t; } for (int i = 1; i <= n; i++) printf("%.3lf ", ans[i]); }
模拟退火
任何函数可行
实现:
先随机一个答案,之后每次在范围内随机一个解,若此解更优则更新,否则以一定概率接受该解
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; #define x first #define y second typedef pair<double, double> PDD; const int N = 110; int n; double ans; PDD a[N]; inline double rand(double l, double r) { return (double)rand() / RAND_MAX * (r - l) + l; } inline double get_dis(PDD a, PDD b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); } inline double calc(PDD X) { double res = 0; for (int i = 1; i <= n; i++) res += get_dis(X, a[i]); ans = min(ans, res); return res; } inline void solve() { PDD cur(rand(0, 10000), rand(0, 10000)); for (double t = 1e4; t > 1e-4; t *= 0.9)//降温,每次缩小范围 { PDD nw(rand(cur.x - t, cur.x + t), rand(cur.y - t, cur.y + t)); double res = calc(nw) - calc(cur); if (exp(-res / t) > rand(0, 1)) cur = nw;//若当前解更优则更新,否则以一定概率接受答案 } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &a[i].x, &a[i].y); ans = 1e8; for (int i = 1; i <= 100; i++) solve();//多退火几次,答案更准确 printf("%.0lf", ans); }