poj1379+POJ2420+hdu3932(最短距离+费马点+模拟淬火算法)

Run Away
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 5632   Accepted: 1729

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

 

题解:

        昨天在网上浏览博客,无意看见有个ACMer交了这题并注明模拟淬火算法,由于在人工智能课上老师提到过这类演化算法-模拟淬火算法。感慨ACM在线OJ还能用模拟淬火算法这类概率算法,于是眼前一亮,有登上好久没有刷题的POJ了,看了道题。

     题意是要求到给定n个点的最小距离最大的点,且点限定在给定矩形内。要是一维的,直接三分找极值即可;在平面上就不太好处理了。且这样的点可能不只一个,到底取谁都要考虑。前人提供了模拟淬火算法,直接搞定了。大致步骤如下:

1、随机选取一个合适的控制条件T作为开始  
2、随机选取P个起始点,作为可行解  
3、分别依据内能更新这P个可行解  
4、减小控制条件T,直到终止条件    
下面是代码:

#include<iostream>
#include<cmath>
#include<ctime>
#include<cstdio>
using namespace std;

const int MAXN=1000+100;
const int KMEAN=30;
const double INF=1<<30;
const double eps=1e-8;
const double PI=3.141592653;
int x,y,n;
struct Point
{
	double x,y;
}myPoint[MAXN],myK[KMEAN];
double dis[KMEAN];

double GetMinDis(double tx,double ty)
{
	double minDis=INF,temp;
	for(int i=0;i<n;i++)
	{
      	temp=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y));
		if(temp<minDis)
	    	minDis=temp;
	}
	return minDis;
}

int main()
{
	int cas,i,j;
	double temp;
	scanf("%d",&cas);
	while(cas--)
	{
		scanf("%d%d%d",&x,&y,&n);
		srand((unsigned)time(NULL));
		for(i=0;i<n;i++)
			scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y);

		for(i=0;i<KMEAN;i++)
		{
			dis[i]=INF;
			myK[i].x=rand()%10001/10000.0*x;
			myK[i].y=rand()%10001/10000.0*y;
		}
		for(i=0;i<KMEAN;i++)
		   dis[i]=GetMinDis(myK[i].x,myK[i].y);

		double theta,delta=1.0*(x>y?x:y)/sqrt(1.0*n);
		while(delta>eps)
		{
			for(i=0;i<KMEAN;i++)
			{
				double nx=myK[i].x,ny=myK[i].y;
				for(j=0;j<KMEAN;j++)
				{
					double tx,ty;
					theta=double(rand()%10001)/10000.0*2*PI;  
					tx=nx+delta*cos(theta);
					ty=ny+delta*sin(theta);
					if(tx<0||tx>x||ty<0||ty>y)
						continue;

					temp=GetMinDis(tx,ty);
					if(temp>dis[i])
					{
						myK[i].x=tx;
						myK[i].y=ty;
						dis[i]=temp;
					}
				}
			}
			delta=0.8*delta;
		}

		int id=-1;
		temp=-INF;
		for(i=0;i<KMEAN;i++)
		{
			if(dis[i]>temp)
			{
				temp=dis[i];
				id=i;
			}
		}
		printf("The safest point is (%.1lf, %.1lf).\n",myK[id].x,myK[id].y);  
	}
	return 0;
}


 

 下面是相似的题

 

A Star not a Tree?
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3274   Accepted: 1666

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

 题解:

       本题与上面那题的唯一区别就是目的函数不同,此处为最短距离和,上面为最短距离的最大者,模拟淬火算法。直接贴代码的。

#include<iostream>
#include<cmath>
#include<ctime>
#include<cstdio>
using namespace std;

const int MAXN=100+10;
const int KMEAN=30;
const double INF=1<<30;
const double eps=1e-8;
const double PI=3.141592653;
double x=10000.0,y=10000.0;
int n;
struct Point
{
	double x,y;
}myPoint[MAXN],myK[KMEAN];
double dis[KMEAN];

double GetMinDis(double tx,double ty)
{
	double temp=0;
	for(int i=0;i<n;i++)
	{
      	temp+=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y));
	}
	return temp;
}

int main()
{
	int i,j;
	double temp;
	while(scanf("%d",&n)!=EOF)
	{
		srand((unsigned)time(NULL));
		for(i=0;i<n;i++)
			scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y);

		for(i=0;i<KMEAN;i++)
		{
			dis[i]=INF;
			myK[i].x=rand()%10001/10000.0*x;
			myK[i].y=rand()%10001/10000.0*y;
		}
		for(i=0;i<KMEAN;i++)
		   dis[i]=GetMinDis(myK[i].x,myK[i].y);

		double theta,delta=10000.0/sqrt(1.0*n);
		while(delta>eps)
		{
			for(i=0;i<KMEAN;i++)
			{
				double nx=myK[i].x,ny=myK[i].y;
				for(j=0;j<KMEAN;j++)
				{
					double tx,ty;
					theta=double(rand()%10001)/10000.0*2*PI;  
					tx=nx+delta*cos(theta);//可改变方向
					ty=ny+delta*sin(theta);
					temp=GetMinDis(tx,ty);
					if(temp<dis[i])
					{
						myK[i].x=tx;
						myK[i].y=ty;
						dis[i]=temp;
					}
				}
			}
			delta=0.98*delta;
		}
		temp=INF;
		for(i=0;i<KMEAN;i++)
		{
			if(dis[i]<temp)
			{
				temp=dis[i];
			}
		}
		printf("%.0lf\n",temp);  
	}
	return 0;
}


 

 下面这题是求最小圆覆盖。

Groundhog Build Home

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1397    Accepted Submission(s): 625


Problem Description
Groundhogs are good at digging holes, their home is a hole, usually a group of groundhogs will find a more suitable area for their activities and build their home at this area .xiaomi has grown up, can no longer live with its parents.so it needs to build its own home.xiaomi like to visit other family so much, at each visit it always start from the point of his own home.Xiaomi will visit all of the groundhogs' home in this area(it will chose the linear distance between two homes).To save energy,xiaomi would like you to help it find where its home built,so that the longest distance between xiaomi's home and the other groundhog's home is minimum.
 


 

Input
The input consists of many test cases,ending of eof.Each test case begins with a line containing three integers X, Y, N separated by space.The numbers satisfy conditions: 1 <= X,Y <=10000, 1 <= N<= 1000. Groundhogs acivity at a rectangular area ,and X, Y is the two side of this rectangle, The number N stands for the number of holes.Then exactly N lines follow, each containing two integer numbers xi and yi (0 <= xi <= X, 0 <= yi <= Y) indicating the coordinates of one home.
 


 

Output
Print exactly two lines for each test case.The first line is the coordinate of xiaomi's home which we help to find. The second line is he longest distance between xiaomi's home and the other groundhog's home.The output round to the nearest number with exactly one digit after the decimal point (0.05 rounds up to 0.1).
 


 

Sample Input
   
   
   
   
1000 50 1 10 10 1000 50 4 0 0 1 0 0 1 1 1
 


 

Sample Output
   
   
   
   
(10.0,10.0). 0.0 (0.5,0.5). 0.7

题解:

      题意是要求到给定n个点的最大距离最小的点,且点限定在给定矩形内,对应数学模型最小点覆盖。贴段代码:

#include<iostream>
#include<cmath>
#include<ctime>
#include<cstdio>
using namespace std;

const int MAXN=1000+100;
const int KMEAN=30;
const double INF=1<<30;
const double eps=1e-8;
const double PI=3.141592653;
int x,y,n;
struct Point
{
	double x,y;
}myPoint[MAXN],myK[KMEAN];
double dis[KMEAN];

double GetMaxDis(double tx,double ty)
{
	double maxDis=-INF,temp;
	for(int i=0;i<n;i++)
	{
      	temp=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y));
		if(temp>maxDis)
	    	maxDis=temp;
	}
	return maxDis;
}

int main()
{
	int i,j;
	double temp;
	while(scanf("%d%d%d",&x,&y,&n)!=EOF)
	{
		srand((unsigned)time(NULL));
		for(i=0;i<n;i++)
			scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y);

		for(i=0;i<KMEAN;i++)
		{
			dis[i]=INF;
			myK[i].x=rand()%10001/10000.0*x;
			myK[i].y=rand()%10001/10000.0*y;
		}
		for(i=0;i<KMEAN;i++)
		   dis[i]=GetMaxDis(myK[i].x,myK[i].y);

		double theta,delta=1.0*(x>y?x:y)/sqrt(1.0*n);
		while(delta>eps)
		{
			for(i=0;i<KMEAN;i++)
			{
				double nx=myK[i].x,ny=myK[i].y;
				for(j=0;j<KMEAN;j++)
				{
					double tx,ty;
					theta=double(rand()%10001)/10000.0*2*PI;  
					tx=nx+delta*cos(theta);
					ty=ny+delta*sin(theta);
					if(tx<0||tx>x||ty<0||ty>y)
						continue;

					temp=GetMaxDis(tx,ty);
					if(temp<dis[i])
					{
						myK[i].x=tx;
						myK[i].y=ty;
						dis[i]=temp;
					}
				}
			}
			delta=0.8*delta;
		}

		int id=-1;
		temp=INF;
		for(i=0;i<KMEAN;i++)
		{
			if(dis[i]<temp)
			{
				temp=dis[i];
				id=i;
			}
		}
		printf("(%.1lf,%.1lf).\n%.1lf\n",myK[id].x,myK[id].y,temp);  
	}
	return 0;
}


 

 

 

你可能感兴趣的:(ACM,模拟淬火)