poj 2420 & poj1379 模拟退火

具体模拟退火的原理可参考  http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html

模拟退火可用于一些  精度  要求不是很高的题目。

比如取答案的0.1,或者没有小数点

poj2420:

/*

题意:给定n个点,找到一个点,使得n个点到这个点的距离和最小
模拟退火法
模拟退火的过程
1 确定生成点的范围,初设为矩形,在这个范围内生成NUM个点(NUM自定)
2 确定最高温度step,以及退温系数,接下来进行退火
3 对于每个生成的点i,在以其为原点,半径为step的!圆周上!,随机生成k个点(注意踢掉不符合的点),一旦有点优于i,则替换。
(由于step的不断缩小,所以总会找到符合的点)
4 缩小范围D,若D<精度,退出,否则执行
5 遍历所有NUM个点,找到val的最大值
*/
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
#define INF 1e20
const double pi=acos(-1.0);
const int maxn=1010;
const int num=20;
struct point
{
    double x,y;
    point(){}
    point(double a,double b){x=a,y=b;}
}p[maxn],may[num+10];//原点,随机生成的点
int n;
double val[num+10];  //价值数组
double maxx,maxy;
double minx,miny;
double Rand()     //随机生成0---1
{
    return double(rand()%1000+1)/1000.000;
}
double dist(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double judge(point tmp)  //判断函数
{
    double len=0;
    for(int i=1;i<=n;i++)
        len+=dist(tmp,p[i]);
    return len;
}
void init()//第一步  生成num个解(包括读入啦)
{
    for(int i=1;i<=num;i++)
    {
        may[i].x=minx+(maxx-minx)*Rand();
        may[i].y=miny+(maxy-miny)*Rand();
        val[i]=judge(may[i]);
    }
}
void solve()
{
    init();    //第一步  生成num个解
    double d,step=sqrt((maxx-minx)*(maxx-minx)+(maxy-miny)*(maxy-miny));  //第二步,确定最高温度  ,最糟糕的step为对角线
    while(step>0.001)
    {
        for(int i=1;i<=num;i++)//第三步,针对每个点
        {
            for(int j=1;j<=30;j++)  //再随机生成若干个解
            {
                d=Rand()*2*pi;  //
                point tmp;
                tmp.x=may[i].x+step*cos(d);
                tmp.y=may[i].y+step*sin(d);  //在may[i]在原点,半径为step的圆周上随机生成点
                if(tmp.x<minx||tmp.x>maxx||tmp.y<miny||tmp.y>maxy) //点在符合的范围内
                    continue;
                double temp=judge(tmp);
                if(temp<val[i])  //优 则替换
                    val[i]=temp,may[i]=tmp;
            }
        }
        step*=0.85;  //第四步,退火
    }
    int idx=1;  //遍历,寻找最优解
    for(int i=2;i<=num;i++)
        if(val[i]<val[idx])
            idx=i;
    printf("%.0lf\n",val[idx]);
}
int main()
{
    srand((unsigned)time(NULL));  //必须的语句,
    while(scanf("%d",&n)!=EOF)
    {
        maxx=-INF,maxy-INF;
        minx=INF,miny=INF;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            maxx=max(maxx,p[i].x);
            maxy=max(maxy,p[i].y);
            minx=min(minx,p[i].x);
            miny=min(miny,p[i].y);
        }
        solve();
    }

}





poj1379:

/*

题意:给定n个点和范围(0,0)--(x,y),在范围内找到一个点,使得n个点到这个点的最小距离最大
模拟退火法
模拟退火的过程
1 确定生成点的范围,在这个范围内生成NUM个点(NUM自定)
2 确定最高温度step,以及退温系数,接下来进行退火
3 对于每个生成的点i,在以其为原点,半径为step的!圆周上!,随机生成k个点(注意踢掉不符合的点),一旦有点优于i,则替换。
(由于step的不断缩小,所以总会找到符合的点)
4 缩小范围D,若D<精度,退出,否则执行
5 遍历所有NUM个点,找到val的最大值
*/
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
const double pi=acos(-1.0);
const int maxn=1010;
const int num=20;
struct point
{
    double x,y;
    point(){}
    point(double a,double b){x=a,y=b;}
}p[maxn],may[num+10];//原点,随机生成的点
int n;
double val[num+10];  //价值数组
double x,y;
double Rand()     //随机生成0---1
{
    return double(rand()%1000+1)/1000.000;
}
double dist(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double judge(point tmp)  //判断函数
{
    double len=10000000000.0;
    for(int i=1;i<=n;i++)
        len=min(len,dist(tmp,p[i]));
    return len;
}
void init()//第一步  生成num个解(包括读入啦)
{
    scanf("%lf%lf%d",&x,&y,&n);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    for(int i=1;i<=num;i++)
    {
        may[i].x=x*Rand();
        may[i].y=y*Rand();
        val[i]=judge(may[i]);
    }
}
void solve()
{
    srand((unsigned)time(NULL));  //必须的语句,
    init();    //第一步  生成num个解
    double d,step=sqrt(x*x+y*y);  //确定最高温度  ,最糟糕的step为对角线
    while(step>0.001)
    {
        for(int i=1;i<=num;i++)
        {
            for(int j=1;j<=30;j++)  //再随机生成若干个解
            {
                d=Rand()*2*pi;  //
                point tmp;
                tmp.x=may[i].x+step*cos(d);
                tmp.y=may[i].y+step*sin(d);  //在may[i]在原点,半径为step的圆周上随机生成点
                if(tmp.x<0||tmp.x>x||tmp.y<0||tmp.y>y)
                continue;
                double temp=judge(tmp);
                if(temp>val[i])  //优 则替换
                    val[i]=temp,may[i]=tmp;
            }
        }
        step*=0.85;  //退火
    }
    int idx=1;
    for(int i=2;i<=num;i++)
        if(val[i]>val[idx])
            idx=i;
    printf("The safest point is (%.1lf, %.1lf).\n",may[idx].x,may[idx].y);
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    solve();
}


























































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值