POJ 1379 Run away & POJ 2420 A star not a Tree [模拟退火] [爬山算法]

POJ 1379 Run Away
Time Limit: 3000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu

Description
One of the traps we will encounter in the Pyramid is located in the Large Room. A lot of small holes are drilled into the floor. They look completely harmless at the first sight. But when activated, they start to throw out very hot java, uh … pardon, lava. Unfortunately, all known paths to the Center Room (where the Sarcophagus is) contain a trigger that activates the trap. The ACM were not able to avoid that. But they have carefully monitored the positions of all the holes. So it is important to find the place in the Large Room that has the maximal distance from all the holes. This place is the safest in the entire room and the archaeologist has to hide there.

Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing three integers X, Y, M separated by space. The numbers satisfy conditions: 1 <= X,Y <=10000, 1 <= M <= 1000. The numbers X and Yindicate the dimensions of the Large Room which has a rectangular shape. The number M stands for the number of holes. Then exactly M lines follow, each containing two integer numbers Ui and Vi (0 <= Ui <= X, 0 <= Vi <= Y) indicating the coordinates of one hole. There may be several holes at the same position.

Output
Print exactly one line for each test case. The line should contain the sentence “The safest point is (P, Q).” where P and Qare the coordinates of the point in the room that has the maximum distance from the nearest hole, rounded to the nearest number with exactly one digit after the decimal point (0.05 rounds up to 0.1).

Sample Input
3
1000 50 1
10 10
100 100 4
10 10
10 90
90 10
90 90
3000 3000 4
1200 85
63 2500
2700 2650
2990 100
Sample Output
The safest point is (1000.0, 50.0).
The safest point is (50.0, 50.0).
The safest point is (1433.0, 1669.8).

Source
Central Europe 1999


这个是爬山算法,而不是模拟退火!!
求一个点到其他说有点的最小距离最大,精度0.1
这个温度T是用在步长上的,而不是选取的概率。
那么显然每次就会越跳越小,逐渐接近最优解。一开始步长选择半对角线长,这样更精确且省时。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
int rnd(int l,int r) { return rand()%(r-l+1)+l; }
const double PI = acos(-1.0);
const int maxn = 1005;
const double T_min = 1e-3;
const double eps = 1e-7;
const int P = 10000;
const double R = 0.9;
const int shift = 100;
const int rp = 15;
const int maxrp = rp + 5;
double X,Y;
struct Point
{
    double x,y;
    Point(const int _x = 0,const int _y = 0) { x = _x; y = _y; }
    bool inside() { return x+eps>0.0 && x-eps<X && y+eps>0.0 && y-eps<Y; }
}point[maxn],temp[maxrp];
double best[maxrp];
int n;
inline void init()
{
    scanf("%lf%lf%d",&X,&Y,&n);
    for(int i=1;i<=n;i++)
    {
        int x0,y0;
        scanf("%d%d",&x0,&y0);
        point[i].x=x0; point[i].y=y0;
    }
}
double dist(Point a,Point b)
{
    double t1 = a.x - b.x;
    double t2 = a.y - b.y;
    return sqrt(t1*t1+t2*t2);
}
double calc(Point now)
{
    double ret = 1e100;
    for(int i=1;i<=n;i++) smin(ret,dist(now,point[i]));
    return ret;
}
Point rand_start()
{
    Point ret;
    ret.x = (double)rnd(0,P)/P*X;
    ret.y = (double)rnd(0,P)/P*Y;
    return ret;
}
Point rand_new(Point now,double T)
{
    double angle = (double)rnd(0,P)/P*2.0*PI;
    now.x += T*cos(angle);
    now.y += T*sin(angle);
    return now;
}
void work()
{
    temp[1]=Point(0.0,0.0);
    temp[2]=Point(0.0,Y);
    temp[3]=Point(X,0.0);
    temp[4]=Point(X,Y);
    for(int i=5;i<=rp;i++) temp[i]=rand_start();
    for(int i=1;i<=rp;i++) best[i]=calc(temp[i]);
    double T = sqrt(X*X+Y*Y)/2.0;
    while(T>T_min)
    {
        for(int i=1;i<=rp;i++)
        {
            Point last = temp[i];
            for(int j=1;j<=shift;j++)
            {
                Point now = rand_new(last,T);
                if(!now.inside()) continue;
                double tmp = calc(now);
                if(tmp > best[i])
                {
                    best[i] = tmp;
                    temp[i] = now;
                }
            }
        }
        T *= R;
    }
    Point ans;
    double mx = 0.0;
    for(int i=1;i<=rp;i++)
        if(best[i]>mx)
        {
            ans = temp[i];
            mx = best[i];
        }
    printf("The safest point is (%.1lf, %.1lf).\n",ans.x,ans.y);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("fire.in","r",stdin);
    freopen("fire.out","w",stdout);
#endif
    srand((unsigned)time(NULL));
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        init();
        work();
    }
    return 0;
}

POJ 2420 A star not a Tree
Description
Luke wants to upgrade his home computer network from 10mbs to 100mbs. His existing network uses 10base2 (coaxial) cables that allow you to connect any number of computers together in a linear arrangement. Luke is particulary proud that he solved a nasty NP-complete problem in order to minimize the total cable length.

Unfortunately, Luke cannot use his existing cabling. The 100mbs system uses 100baseT (twisted pair) cables. Each 100baseT cable connects only two devices: either two network cards or a network card and a hub. (A hub is an electronic device that interconnects several cables.) Luke has a choice: He can buy 2N-2 network cards and connect his N computers together by inserting one or more cards into each computer and connecting them all together. Or he can buy N network cards and a hub and connect each of his N computers to the hub. The first approach would require that Luke configure his operating system to forward network traffic. However, with the installation of Winux 2007.2, Luke discovered that network forwarding no longer worked. He couldn’t figure out how to re-enable forwarding, and he had never heard of Prim or Kruskal, so he settled on the second approach: N network cards and a hub.

Luke lives in a loft and so is prepared to run the cables and place the hub anywhere. But he won’t move his computers. He wants to minimize the total length of cable he must buy.

Input
The first line of input contains a positive integer N <= 100, the number of computers. N lines follow; each gives the (x,y) coordinates (in mm.) of a computer within the room. All coordinates are integers between 0 and 10,000.

Output
Output consists of one number, the total length of the cable segments, rounded to the nearest mm.

Sample Input
4
0 0
0 10000
10000 10000
10000 0
Sample Output
28284

Source
Waterloo Local 2002.01.26


用爬山算法是类似的一道题,这个要求费马点。。
和上一道题不一样,此题没有边界范围,所以要用最小的矩形框出一个范围。
此题采用矩形中rand点的方式,上一道题rand角度,当然rand角度也可以。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
inline int rnd(int l,int r) { return rand()%(r-l+1)+l; }
const double PI = acos(-1.0);
const double eps = 1e-7;
const int maxn = 105;
const int P = 10000;
const int shift = 100;
const int rp = 15;
const int maxrp = rp + 3;
const double T_min = 0.1;
const double R = 0.9;
struct Point
{
    double x,y;
    Point(const double _x = 0,const double _y = 0) { x=_x;y=_y; }
}point[maxn],temp[maxn];
double best[maxn];
int n;
double min_x,max_x,min_y,max_y;
inline double dist(Point a,Point b)
{
    double t1 = a.x - b.x;
    double t2 = a.y - b.y;
    return sqrt(t1*t1+t2*t2);
}
inline double calc(Point now)
{
    double ret = 0.0;
    for(int i=1;i<=n;i++) ret += dist(now,point[i]);
    return ret;
}
void init()
{
    min_x = 1e100 , min_y = 1e100;
    max_x = -1e100 , max_y = -1e100;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        point[i].x=(double)x;
        point[i].y=(double)y;
        smin(min_x,point[i].x); smax(max_x,point[i].x);
        smin(min_y,point[i].y); smax(max_y,point[i].y);
    }
}
Point rand_range(Point a,Point b)
{
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    dx *= (double)rnd(0,P)/P;
    dy *= (double)rnd(0,P)/P;
    return Point(a.x+dx,a.y+dy);
}
Point rand_angle(Point now,double T)
{
    double angle = (double)rnd(0,P)/P*2.0*PI;
    now.x += T*cos(angle);
    now.y += T*sin(angle);
    return now;
}
void work()
{
    temp[1]=Point(min_x,min_y);
    temp[2]=Point(max_x,min_y);
    temp[3]=Point(min_x,max_y);
    temp[4]=Point(max_x,max_y);
    temp[5]=Point((min_x+max_x)/2,(min_y+max_y)/2);
    for(int i=6;i<=rp;i++) temp[i]=rand_range(temp[1],temp[4]);
    for(int i=1;i<=rp;i++) best[i]=calc(temp[i]);
    double T = max(max_x-min_x,max_y-min_y);
    while(T > T_min)
    {
        for(int i=1;i<=rp;i++)
        {
            Point last = temp[i];
            for(int j=1;j<=shift;j++)
            {
                Point now = rand_range(Point(last.x-T,last.y-T),Point(last.x+T,last.y+T));
                //Point now = rand_angle(last,T);
                double tmp = calc(now);
                if(now.x<min_x-eps||now.x>max_x+eps||now.y<min_y-eps||now.y>max_y+eps) continue;
                if(tmp<best[i])
                {
                    best[i] = tmp;
                    temp[i] = now;
                }
            }
        }
        T *= R;
    }
    double ans = 1e100;
    for(int i=1;i<=rp;i++) smin(ans,best[i]);
    printf("%.0lf",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("star.in","r",stdin);
    freopen("star.out","w",stdout);
#endif
    srand((unsigned)time(NULL));
    init();
    work();
    //cout<<endl<<(double)clock()/CLOCKS_PER_SEC<<endl;
    return 0;
}


而模拟退火是要按照与温度有关的概率来接受劣点,这样的活可以有一定概率避免得到局部最优解。
这个方法是hzwer的,每次将当前点到n个点的位移加起来,这样相当于按照离散程度来rand,行之有效。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int P = 10000;
const int maxn = 105;
const int rp = 10;
const int maxrp = rp + 5;
const double T_min = 0.1;
const double R = 0.9;
inline int rnd(int l,int r) { return rand()%(r-l+1)+l; }
inline double rnd01() { return (double)rnd(0,P)/P; }
struct Point
{
    double x,y;
    Point(const double _x = 0,const double _y = 0) { x=_x; y=_y; }
}point[maxn],temp[maxrp];
double best[maxrp];
int n;
inline double dist(Point a,Point b)
{
    double t1 = a.x - b.x;
    double t2 = a.y - b.y;
    return sqrt(t1*t1+t2*t2);
}
inline double calc(Point now)
{
    double ret = 0.0;
    for(int i=1;i<=n;i++) ret += dist(now,point[i]);
    return ret;
}
double min_x,max_x,min_y,max_y;
double xx,yy;
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        double x,y;
        scanf("%lf%lf",&x,&y);
        xx += x; yy += y;
        smin(min_x,x); smax(max_x,x);
        smin(min_y,y); smax(max_y,y);
        point[i] = Point(x,y);
    }
    xx /= n; yy /= n;
}
Point rand_range(Point a,Point b)
{
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    dx *= rnd01(); dy *= rnd01();
    return Point(a.x+dx,a.y+dy);
}
void work()
{
    temp[1] = Point(min_x,max_x);
    temp[2] = Point(max_x,min_y);
    temp[3] = Point(min_x,max_y);
    temp[4] = Point(max_x,max_y);
    temp[5] = Point((min_x+max_x)/2,(min_y+max_y)/2);
    temp[6] = Point(xx,yy);
    for(int i=7;i<=rp;i++) temp[i] = rand_range(temp[1],temp[4]);
    for(int i=1;i<=rp;i++) best[i] = calc(temp[i]);
    double T = max(max_x-min_x,max_y-min_y);
    while(T > T_min)
    {
        for(int i=1;i<=rp;i++)
        {
            double sumx = 0.0 , sumy = 0.0;
            for(int j=1;j<=n;j++)
            {
                sumx += (point[j].x-temp[i].x)/dist(point[j],temp[i]);
                sumy += (point[j].y-temp[i].y)/dist(point[j],temp[i]);
            }
            Point now = Point(temp[i].x+sumx*T,temp[i].y+sumy*T);
            double tmp = calc(now);
            if(tmp <= best[i] || exp((best[i]-tmp)/T) > rnd01()) temp[i]=now,best[i]=tmp;
        }
        T *= R;
    }
    double ans = 1e100;
    for(int i=1;i<=rp;i++) smin(ans,best[i]);
    printf("%.0lf",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("star.in","r",stdin);
    freopen("star.out","w",stdout);
#endif
    srand((unsigned)time(NULL));
    init();
    work();
    //cout<<endl<<(double)clock()/CLOCKS_PER_SEC<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值