您的位置:首页 > 其它

模拟退火合集

2014-10-01 23:50 260 查看

hdu 3644 A Chocolate Manufacturer's Problem

首次接触模拟退火,看来还是挺神奇的。

主要参考这篇博文:http://blog.sina.com.cn/s/blog_7da04dd30100wlqj.html

题意判断多边形内部能否容纳一个半径为R的圆,即在有限的平面内找最优范围。遗传算法的结果难以掌控,爬山算法又没法保证跳出局部最优,所以基于贪心原则的模拟退火算法还是值得考虑的。

然后就是设定每次变化的步长和演化方式。该题可以从每条边的中点开始,向一个随机方向延伸,使找出的点到各条边的最小距离最大。

#include <stdio.h>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
#ifdef __GNUC__
typedef long long LL;
inline void opt64(LL a) {
printf("%lld", a);
}
#else
typedef __int64 LL;
inline void opt64(LL a) {
printf("%I64d", a);
}
#endif
const int MAXN = 55, maxstps = 6;
const double inf = 1e20, eps = 1e-3, aeps = 1e-3;
int n;
double radius;
inline int cmp(double x, double y) {
return ((x-y)>aeps) - ((x-y)<-aeps);
}
inline int cmp(double x) {
return (x>aeps) - (x<-aeps);
}
struct _point
{
double x, y, r;
_point(double xx=0.0, double yy=0.0):x(xx),y(yy) {}
void ipt() {
scanf("%lf%lf", &x, &y);
}
double dot(const _point &a) {
return x*a.x+y*a.y;
}
double cross(const _point &a) {
return x*a.y-y*a.x;
}
_point operator + (const _point &a) {
return _point(x+a.x, y+a.y);
}
_point operator - (const _point &a) {
return _point(x-a.x, y-a.y);
}
double dis() {
return sqrt(x*x + y*y);
}
} da[MAXN], db[MAXN];
bool point_in_poly(_point p)
{
_point q = p, a, b;
q.x = inf;
int res = 0;
double x;
for (int i = 0; i< n; ++i)
{
a = da[i];
b = da[1+i];
if (cmp(a.y, b.y) == 0 ||
cmp(p.y, min(a.y, b.y)) == -1 ||
cmp(p.y, max(a.y, b.y)) >= 0 ) continue;
x = (p.y-a.y)*(b.x - a.x) / (b.y - a.y) + a.x;
if (cmp(x, p.x) == 0) return 0;
if (cmp(x, p.x) == 1) ++res;
}
return res%2;
}
double dis_Point_to_seg(_point o, _point a, _point b)
{
_point l1 = o-a, l2 = o-b, l3 = a-b;
if (cmp(l1.dot(l3)) == 1) return l1.dis();
if (cmp(l2.dot(l3)) == -1) return l2.dis();
return fabs(l1.cross(l2)) / l3.dis();
}
void cal(_point * a)
{
a->r = inf;
for (int i = 0; i< n; ++i)
a->r = min( dis_Point_to_seg(*a, da[i], da[i+1]), a->r);
}
int solve(double r)
{
_point tmp;
double agl;
while (r > eps)
{
for (int i = 0; i< n; ++i)
{
for (int j = 0; j< maxstps; ++j)
{
agl = rand();
tmp.x = db[i].x + cos(agl)*r;
tmp.y = db[i].y + sin(agl)*r;
if (point_in_poly(tmp))
{
cal(&tmp);
if (tmp.r > db[i].r)
{
db[i] = tmp;
if (cmp(tmp.r, radius) >= 0)
return 1;
}
}

}
}
r *= 0.9;
}
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (scanf("%d", &n) && n)
{
double maxx = -1, maxy = -1, minx = inf, miny = inf;
for (int i = 0; i< n; ++i)
da[i].ipt(), maxx = max(maxx, da[i].x), maxy = max(maxy, da[i].y),
minx = min(minx, da[i].x), miny = min(miny, da[i].y);
da
= da[0];
for (int i = 0; i< n; ++i)
{
db[i].x = (da[i].x + da[i+1].x)/2.0;
db[i].y = (da[i].y + da[i+1].y)/2.0;
db[i].r = 0.0;
}
maxx = maxx - minx;
maxy = maxy - miny;
scanf("%lf", &radius);
if (solve(sqrt(maxx*maxx + maxy*maxy)/2.0)) puts("Yes");
else puts("No");
}
return 0;
}


hdu 5017 Ellipsoid

找出椭球面上距离球心最近的点

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-10, r = 0.99;
double a, b, c, d, e, f, res;
double dir[8][2] = {0,1, 0,-1, -1,0, 1,0, -1,1, -1,-1, 1,1, 1,-1};
inline double dis (double x, double y, double z)
{
return sqrt(x*x + y*y + z*z);
}
inline int cmp(double x)
{
return (x>eps) - (x<-eps);
}
int cal(double A, double B, double C, double &z)
{
double q = B*B - 4*A*C;
if (cmp(q) < 0) return 0;
z = (sqrt(q) - B)/A/2.0;
return 1;
}
void solve()
{
double x=0, y=0, z, k = 1.0, ax=0, ay=0, pp;
cal(c, 0, -1, z);
res = dis(0, 0, z);
while (k > eps)
{
x = ax; y = ay;
for (int i = 0; i< 8; ++i)
{
double xx = x+dir[i][0]*k, yy = y+dir[i][1]*k;
if (cal(c, d*yy+e*xx, a*xx*xx+b*yy*yy+f*xx*yy-1, z) == 0) continue;
if ( cmp((pp=dis(xx, yy, z)) - res) < 0)
ax = xx, ay = yy, res = pp;
}
k *= r;
}
printf("%.7lf\n", res);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
while (scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &e, &f) != EOF)
{
solve();
}
return 0;
}


hdu 3932 Groundhog Build Home

最小覆盖圆

#include <stdio.h>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
#ifdef __GNUC__
typedef long long LL;
inline void opt64(LL a) {
printf("%lld", a);
}
#else
typedef __int64 LL;
inline void opt64(LL a) {
printf("%I64d", a);
}
#endif
const int MAXN = 1005, maxstps = 5;
const double inf = 1e20, eps = 1e-4, aeps = 1e-6;
int n;
double radius;
double maxx = -1, maxy = -1, minx = inf, miny = inf;
inline int cmp(double x, double y) {
return ((x-y)>aeps) - ((x-y)<-aeps);
}
inline int cmp(double x) {
return (x>aeps) - (x<-aeps);
}
struct _point
{
double x, y;
_point(double xx=0.0, double yy=0.0):x(xx),y(yy) {}
void ipt() {
scanf("%lf%lf", &x, &y);
}
_point operator - (const _point &a) {
return _point(x-a.x, y-a.y);
}
double dis() {
return sqrt(x*x + y*y);
}
} da[MAXN];
inline bool point_in_rect(double x, double y)
{
if (cmp(x-maxx) == 1 ||
cmp(x-minx) == -1 ||
cmp(y-maxy) == 1 ||
cmp(y-miny) == -1) return 0;
return 1;
}
void solve(double x, double y, double r, double mxdis)
{
double angle, xx=x, yy=y, ax, ay, d, c;
while (r > eps)
{
x = xx; y = yy;
for (angle = 0.0; angle< 6.28; angle += 0.1)
{
ax = x+cos(angle)*r; ay=y+sin(angle)*r;
if (point_in_rect(ax,ay))
{
_point ap(ax,ay);
c = -1;
for (int j = 0; j< n; ++j)
{
d = (ap-da[j]).dis();
if (cmp(d-c)==1)
c = d;
}
if (cmp(c-mxdis)==-1)
{
mxdis = c;
xx = ax; yy = ay;
}
}
}
r *= 0.7;
}
printf("(%.1lf,%.1lf).\n", x, y);
printf("%.1lf\n", mxdis);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (scanf("%lf%lf%d", &maxx, &maxy, &n) != EOF)
{
minx = 0.0, miny = 0.0;
double x1=inf, x2=-1, y1=inf, y2=-1, c=-1;
for (int i = 0; i< n; ++i)
da[i].ipt(), x1=min(x1,da[i].x),
x2=max(x2, da[i].x), y1=min(y1,da[i].y), y2=max(y2,da[i].y);
_point pp((x1+x2)/2, (y1+y2)/2);
for (int i = 0; i< n; ++i)
c = max(c, (pp-da[i]).dis());
solve(pp.x, pp.y, sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))*0.5, c);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  模拟退火