USACO 5.2 electic fences——模拟退火

我的第一个模拟退火算法,呵呵~所谓的模拟退火,实际上就是局部搜索和随机算法的结合版~爬山算法的升级版~

关于模拟退火比较容易懂的材料,可以看这里:http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html

模拟退火仅仅是一个模型,其参数需要根据实际情况适当设置,如果参数设置得当,那么该算啊很容易找到最优解,而且正确性和效率都还不错。

由模拟退火的概率计算公式——p=exp(d/t)可以发现,最优解的分布有一定概率密度关系时这种算法最适合= =,说的有点绕。

 

/*
ID: zlqest11
LANG: C++
TASK: fence3
*/

#include <iostream>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define sqr(a) (a)*(a)

const int N = 155;
struct node{
int x1, y1, x2, y2;
}p[N];
int n;

double Cal(double x, double y, int k){
double tmp1, tmp2;
if(p[k].x1 == p[k].x2)
if(y>=p[k].y1 && y<=p[k].y2) return fabs(x-p[k].x1);
if(p[k].y1 == p[k].y2)
if(x>=p[k].x1 && x<=p[k].x2) return fabs(y-p[k].y1);
tmp1 = sqrt(sqr(p[k].x1-x)+sqr(p[k].y1-y));
tmp2 = sqrt(sqr(p[k].x2-x)+sqr(p[k].y2-y));
return min(tmp1, tmp2);
}

int main()
{
int ct = 11;
freopen("fence3.in", "r", stdin);
freopen("fence3.out", "w", stdout);
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d%d%d%d", &p[i].x1, &p[i].y1, &p[i].x2, &p[i].y2);
if(p[i].x1==p[i].x2 && p[i].y1>p[i].y2) swap(p[i].y1, p[i].y2);
if(p[i].y1==p[i].y2 && p[i].x1>p[i].x2) swap(p[i].x1, p[i].x2);
}
double x=rand()%101, y=rand()%101, ans=0.0, t=100, tarx, tary;
for(int i = 0; i < n; i++) ans += Cal(x, y, i);
srand((int)time(0));
while(t > 1e-2){
double temp, d, tx, ty, p;
for(int k = 0; k < 500; k++){
temp = 0.0;
tx = t*(rand()*1.0/RAND_MAX)*(2*(rand()%2)-1);
ty = sqrt(sqr(t)-sqr(tx))*(2*(rand()%2)-1);
tx += x, ty += y;
for(int i = 0; i < n; i++) temp += Cal(tx, ty, i);
d = temp-ans;
if(d < 0){
p = 1.1;
tarx = tx;
tary = ty;
ans = temp;
}
else p = exp(-d/t);
double q = rand()*1.0/RAND_MAX;
if(p > q){
x = tx, y = ty;
}
}
ct++;
t /= log10(ct);
}
printf("%.1f %.1f %.1f\n", tarx, tary, ans);
return 0;
}



你可能感兴趣的:(USACO)