POJ2420爬山算法、模拟退火入门之n个定点的覆盖

A Star not a Tree?

 

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

题意:

题目的意思就是给你N个点,在平面上寻找一个点,使得这个点到其他点的距离之和最小,问你最小的距离是多

少?

分析:在三角形内部这个点叫做费马点,那么在这道题目中,使用DFS的思想,以概率的方式将可能的点试一遍,首先将这些区域里面的点全部遍历一遍肯定会T掉,不能使用枚举的方法,于是想到随机点出来比较,那么这就用到爬山算法(其实就是一种类似贪心或者是暴力的方法),如果是找最小的距离,那么这个点一定是在这些点里面,那么就不妨一开始设第一个输入的点为初始点,然后再去判断,判断的时候就将当前这个点的上下左右四个点全部遍历一遍,然后看是否去更新答案

参考这个https://www.cnblogs.com/Robert-Yuan/p/5033878.html

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
    double x,y;
}num[200];
    int n;
double dis(node a,node b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double sumdis(node p){
    double sum=0.0;
    for(int i=0;i<n;i++)
    sum+=dis(p,num[i]);
    return sum;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    while(scanf("%d",&n)!=EOF){
        double xx=0.0;
        for(int i=0;i<n;i++) scanf("%lf%lf",&num[i].x,&num[i].y);
        double step=10000;//因为题目中的范围是0 and 10,000.,因此不妨设一开始就是10000,那么
        //以这个为距离的四个方向全部遍历一遍,进而再去缩小这个范围
        node p=num[0];
        double ans=sumdis(p);
        while(step>0.2){
            node q;
            for(int i=-1;i<=1;i++){
                for(int j=-1;j<=1;j++){
                    q.x=p.x+step*i;
                    q.y=p.y+step*j;
                    double res=sumdis(q);
                    if(res<ans){
                        ans=res;
                        p=q;
                    }
                }
            }
            step/=2.0;
        }
        printf("%.0f\n",ans);
    }
}

下面是我参考的另外的代码,其实下面的这一个应该是一个模拟退火,我上面的自己写的应该是爬山算法,

模拟退火就是在爬山算法的基础上又新增加了一个 以一定概率接受最优解。

就是一个exp 比一个随机在(0,1)的概率小,就接受。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
const int maxn=105;
using namespace std;
int n;
int xi[maxn],yi[maxn];
double sum(double x,double y)
{
	double ans=0;
	for(int i=1;i<=n;i++)
	{
		ans+=sqrt((x-xi[i])*(x-xi[i])+(y-yi[i])*(y-yi[i]));
	}
	return ans;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)scanf("%d%d",&xi[i],&yi[i]);
		double step=100000;
		double x=xi[1],y=yi[1];
		while(step>1e-9)
		{
			double rad=rand()%360+1;
			double nx=x+step*cos(rad);
			double ny=y+step*sin(rad);
			if(sum(nx,ny)<sum(x,y))
			{
				x=nx;
				y=ny;
			}
			step*=0.99;
		}
		printf("%.0f\n",sum(x,y));
	}
	return 0;
}

也可以这样处理

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
double INF=1000000000;
const double PI = acos(-1.0);
int n;
struct node{
    double x,y;
}num[2000],moni[30];
double ux,uy;
double dis(node a,node b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve(node p){

    double ans=0;
    for(int i=0;i<n;i++)
        ans+=dis(p,num[i]);
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    scanf("%d",&n);
    double t=10000;//初始化温度T
    rep(i,0,n-1) scanf("%lf%lf",&num[i].x,&num[i].y);
    rep(i,0,19){//随机化20组答案
    moni[i].x=ux*((rand() % 1000+1.0)/ 1000.0);//保证区间是[0,1]
    moni[i].y=uy*((rand() % 1000+1.0) / 1000.0);
    }
    while(t>1e-3){
            node q;
        for(int j=0;j<20;j++){
          double ans=solve(moni[j]);
        for(int i=0;i<30;i++){
       double k= (rand() % 1000+1.0)/ 1000.0 * 2 * PI;
        q.x=moni[j].x+sin(k)*t;
        q.y=moni[j].y+cos(k)*t;
        double res=solve(q);
        if(res<ans){//更新最优解
            ans=res;
            moni[j]=q;
           }
            else if(exp(res/t)<(double)rand()/(double)RAND_MAX){//返回[0,1]内的数,当然也可用(rand() % 1000+1.0)/ 1000.0
            ans=res,moni[j]=q;
            }
          }
        }
        t*=0.9;
    }
    double ans=INF;
    int k;
    for(int i=0;i<20;i++){
            double res=solve(moni[i]);
          if(res<ans){
            ans=res;
            k=i;
        }
    }
    printf("%.0f\n",ans);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值