您的位置:首页 > 其它

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

2016-10-07 00:24 471 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息