模拟退火

一定要%mmh学长。
例①:P1337 [JSOI2004]平衡点 / 吊打XXX:
题目描述
如图:有n个重物,每个重物系在一条足够长的绳子上。每条绳子自上而下穿过桌面上的洞,然后系在一起。图中X处就是公共的绳结。假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到地上),且忽略所有的摩擦。

问绳结X最终平衡于何处。

注意:桌面上的洞都比绳结X小得多,所以即使某个重物特别重,绳结X也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。
输入格式
文件的第一行为一个正整数n(1≤n≤1000),表示重物和洞的数目。接下来的n行,每行是3个整数:Xi.Yi.Wi,分别表示第i个洞的坐标以及第 i个重物的重量。(-10000≤x,y≤10000, 0<w≤1000 )

输出格式
你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结X的横坐标和纵坐标。两个数以一个空格隔开。

输入输出样例
输入 #1 复制
3
0 0 1
0 2 1
1 1 1
输出 #1 复制
0.577 1.000
说明/提示
[JSOI]

真—玄学算法,一直过不了,修改了一下随机种子,跑了两遍SA就过了。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int maxn=1010;
const double delta=0.995;
const double eps=1e-14;
struct node
{
    double x,y,w;
}a[maxn];
int n;
double sumx,sumy,ansx,ansy;
double ans=1e18,t;

double fi(double x,double y)
{
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=sqrt((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y))*a[i].w;
    }
    return ans;
}

void SA(void)
{
    t=2000;
    double x=ansx,y=ansy;
    while(t>eps)
    {
        double xx=x+((rand()<<1)-RAND_MAX)*t;
        double yy=y+((rand()<<1)-RAND_MAX)*t;
        double now=fi(xx,yy);
        double e=now-ans;
        if(e<0)
        {
            x=xx,y=yy;
            ansx=x,ansy=y,ans=now;
        }
        else if(exp(-e/t)*RAND_MAX>rand()) x=xx,y=yy;
        t*=delta;
    }
}

int main(void)
{
    srand(19981031);
    srand(rand()),srand(rand());
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].w);
        sumx+=a[i].x,sumy+=a[i].y;
    }
    //从平均值开始
    ansx=sumx/n,ansy=sumy/n;
    SA();SA();
    printf("%.3f %.3f\n",ansx,ansy);
    return 0;

}

例②:POJ 2420 A Star not a Tree?
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11094 Accepted: 4576
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

给n个点,找出一个点,使这个点到其他所有点的距离之和最小。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int maxn=110;
const double delta=0.995;
const double eps=1e-14;
struct node
{
    double x,y;
}a[maxn];
int n;
double sumx,sumy,ansx,ansy;
double ans=1e18,t;

double fi(double x,double y)
{
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=sqrt((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y));
    }
    return ans;
}

void SA(void)
{
    t=10000;
    double x=ansx,y=ansy;
    while(t>eps)
    {
        double xx=x+((rand()<<1)-RAND_MAX)*t;
        double yy=y+((rand()<<1)-RAND_MAX)*t;
        double now=fi(xx,yy);
        double e=now-ans;
        if(e<0)
        {
            x=xx,y=yy;
            ansx=x,ansy=y,ans=now;
        }
        else if(exp(-e/t)*RAND_MAX>rand()) x=xx,y=yy;
        t*=delta;
    }
}

int main(void)
{
    srand(19981031);
    srand(rand()),srand(rand());
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&a[i].x,&a[i].y);
        sumx+=a[i].x,sumy+=a[i].y;
    }
    //从平均值开始
    ansx=sumx/n,ansy=sumy/n;
    SA();
    printf("%.0f\n",ans);
    return 0;

}

例③:POJ 1379 Run Away
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 11282 Accepted: 3309
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).

给定若干个点,求(0,0)到(x,y)中哪个点距离给定点的最小距离最大。
突然感觉好难啊,完全get不到该怎么退火。。。
找到一些随机点,从这些点出发,随机的方向坐标向外搜索;
最后找到这些随机点的最大值;

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int maxn=1010;
const double delta=0.98;
const double eps=1e-3;
const double pi=acos(-1.0);
const int maxp=21;
const int p=10000;
struct node
{
    double x,y;
}a[maxn];
int n;
double ansx[maxp],ansy[maxp];
double ans[maxp],t,xx,yy;
int bx,by;

double fi(double x,double y)
{
    double ans=1e18;
    for(int i=1;i<=n;i++)
    {
        ans=min(ans,sqrt((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y)));
    }
    return ans;
}

void SA(void)
{
    t=max(bx,by);
    while(t>eps)
    {
        for(int i=1;i<maxp;i++)
        {
            double x=ansx[i],y=ansy[i];
            double angle=(rand()%p+1)*1.0/p*2*pi;
            x+=cos(angle)*t*((rand()%p+1)*1.0/p);
            y+=sin(angle)*t*((rand()%p+1)*1.0/p);
            
			if(x<0||y<0||x>bx||y>by) continue;

            double now=fi(x,y);
            if(now>ans[i])
            {
            	ansx[i]=x;
				ansy[i]=y;
				ans[i]=now;
			}    
        }
        t*=delta;
    }
    double now=0;
    for(int i=1;i<maxp;i++)
    {
        if(ans[i]>now)
        {
            now=ans[i];
            xx=ansx[i];
            yy=ansy[i];
        }
    }
}

int main(void)
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        srand(19981031);
        srand(rand()),srand(rand());
        scanf("%d%d%d",&bx,&by,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&a[i].x,&a[i].y);
        }
        for(int i=1;i<maxp;i++)
        {
            ansx[i]=(rand()%p+1)*1.0/p*bx;
            ansy[i]=(rand()%p+1)*1.0/p*by;
            ans[i]=0;
        }
        SA();
        printf("The safest point is (%.1f, %.1f).\n",xx,yy);

    }
    return 0;

}

例④:POJ 2069 Super Star
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7653 Accepted: 1856 Special Judge
Description

During a voyage of the starship Hakodate-maru (see Problem 1406), researchers found strange synchronized movements of stars. Having heard these observations, Dr. Extreme proposed a theory of “super stars”. Do not take this term as a description of actors or singers. It is a revolutionary theory in astronomy.
According to this theory, starts we are observing are not independent objects, but only small portions of larger objects called super stars. A super star is filled with invisible (or transparent) material, and only a number of points inside or on its surface shine. These points are observed as stars by us.

In order to verify this theory, Dr. Extreme wants to build motion equations of super stars and to compare the solutions of these equations with observed movements of stars. As the first step, he assumes that a super star is sphere-shaped, and has the smallest possible radius such that the sphere contains all given stars in or on it. This assumption makes it possible to estimate the volume of a super star, and thus its mass (the density of the invisible material is known).

You are asked to help Dr. Extreme by writing a program which, given the locations of a number of stars, finds the smallest sphere containing all of them in or on it. In this computation, you should ignore the sizes of stars. In other words, a star should be regarded as a point. You may assume the universe is a Euclidean space.
Input

The input consists of multiple data sets. Each data set is given in the following format.

n
x1 y1 z1
x2 y2 z2
. . .
xn yn zn

The first line of a data set contains an integer n, which is the number of points. It satisfies the condition 4 <= n <= 30.

The location of n points are given by three-dimensional orthogonal coordinates: (xi, yi, zi) (i = 1, …, n). Three coordinates of a point appear in a line, separated by a space character. Each value is given by a decimal fraction, and is between 0.0 and 100.0 (both ends inclusive). Points are at least 0.01 distant from each other.

The end of the input is indicated by a line containing a zero.
Output

For each data set, the radius of the smallest sphere containing all given points should be printed, each in a separate line. The printed values should have 5 digits after the decimal point. They may not have an error greater than 0.00001.
Sample Input

4
10.00000 10.00000 10.00000
20.00000 10.00000 10.00000
20.00000 20.00000 10.00000
10.00000 20.00000 10.00000
4
10.00000 10.00000 10.00000
10.00000 50.00000 50.00000
50.00000 10.00000 50.00000
50.00000 50.00000 10.00000
0
Sample Output

7.07107
34.64102
最小球覆盖,不断向最远点靠近,感觉写起来比较像爬山算法。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define llu unsigned ll
//#define int ll
using namespace std;
const int maxn=50;
const double delta=0.985;
const double eps=1e-14;
const double pi=acos(-1.0);
struct node
{
    double x,y,z;
}a[maxn];
int n;
double ansx,ansy,ansz,ans=1e18,t;
double sumx,sumy,sumz;
double dis(int i)
{
    return sqrt((ansx-a[i].x)*(ansx-a[i].x)+(ansy-a[i].y)*(ansy-a[i].y)+(ansz-a[i].z)*(ansz-a[i].z));
}

void SA(void)
{
    t=100;
    double x=ansx,y=ansy,z=ansz;
    while(t>eps)
    {
        double maxans=0;
        int id=0;
        for(int i=1;i<=n;i++)
        {
            if(dis(i)>maxans) maxans=dis(i),id=i;
        }
        ans=min(ans,maxans);
        //逐步向最远点靠近
        ansx+=(a[id].x-ansx)/maxans*t;
        ansy+=(a[id].y-ansy)/maxans*t;
        ansz+=(a[id].z-ansz)/maxans*t;
        t*=delta;
    }
}

int main(void)
{

    while(scanf("%d",&n),n)
    {
        srand(19981031);
        srand(rand()),srand(rand());
        sumx=sumy=sumz=0;
        ans=1e18;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].z);
            sumx+=a[i].x,sumy+=a[i].y,sumz+=a[i].z;
        }
        ansx=sumx/n,ansy=sumy/n,ansz=sumz/n;
        SA();
        printf("%.5f\n",ans);
    }
    return 0;

}

一开始还觉得挺简单的。。。
可是现在完全get不到该怎么模拟退火。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值