2021-08-11

题目
只要数学,贪心,几何和枚举学得好,这题就很简单。但是本菜鸡不行啊。
解决的方法是,先得到所有两点间的距离,接着排序,选取最短距离的两个点作为起点。
设已经停止增长的点集合为 V 1 V_{1} V1,正在增长的点集合为 V 2 V_{2} V2
对于一个点 a a a,计算与集合 V 1 V_{1} V1所形成的圆的最短距离,以 V 1 V_{1} V1中的某个点 b b b为例,两个点的距离为 d a b = ( x a − x b ) 2 + ( y a − y b ) 2 d_{ab}=\sqrt{(x_{a}-x_{b})^{2}+(y_{a}-y_{b})^{2}} dab=(xaxb)2+(yayb)2 ,点 a a a所形成的圆的半径为 r 1 = d − r b r_{1}=d-r_{b} r1=drb
V 2 V_{2} V2中的某个点 c c c为例,两点的距离为 d a c = ( x a − x c ) 2 + ( y a − y c ) 2 d_{ac}=\sqrt{(x_{a}-x_{c})^{2}+(y_{a}-y_{c})^{2}} dac=(xaxc)2+(yayc)2 ,点 a a a所形成的圆的半径为 r 2 = 0.5 d r_{2}=0.5d r2=0.5d
对于点 a a a,比较该点与剩余的点中的 r 1 r_{1} r1 r 2 r_{2} r2哪一个更小(第二次补题,依然败在这个上面),从而得到结果。当然,不论集合 V 1 V_{1} V1 V 2 V_{2} V2的点都要进行这样的枚举,即为 n − 1 n-1 n1次(从整体情况上这么判断)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const int N=2020;

struct node{
	ll x, y;
	double r;
	bool vis;
}a[N];

struct link{
	int index1, index2;
	double dis;
	bool flag;
};

double distance(node a, node b){
	return sqrt(pow(a.x-b.x, 2)+pow(a.y-b.y, 2));
}

bool operator < (link a, link b){
	return a.dis > b.dis;
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1; i<=n; i++){
    	scanf("%lld%lld", &a[i].x, &a[i].y);
    	a[i].vis=false;
    }

    priority_queue<link> que;
    link temp;
    int cnt=0;
    double ans=0;

    for(int i=1; i<n; i++){
    	for(int j=i+1; j<=n; j++){
    		temp.index1=i, temp.index2=j;
    		temp.dis=distance(a[i], a[j])/2;
    		temp.flag=false;
    		que.push(temp);
    	}
    }

    while(cnt<n){
    	temp=que.top();
    	que.pop();

    	if(a[temp.index1].vis && a[temp.index2].vis){
    		continue;
    	} else if(a[temp.index1].vis){
    		if(temp.flag){
    			a[temp.index2].r=temp.dis;
    			ans+=PI*a[temp.index2].r*a[temp.index2].r;
    			a[temp.index2].vis=true;
    			cnt+=1;
    		} else {
    			temp.dis=distance(a[temp.index1], a[temp.index2])-a[temp.index1].r;
    			temp.flag=true;
    			que.push(temp);
    		}
    	}  else if(a[temp.index2].vis){
    		if(temp.flag){
    			a[temp.index1].r=temp.dis;
    			ans+=PI*a[temp.index1].r*a[temp.index1].r;
    			a[temp.index1].vis=true;
    			cnt+=1;
    		} else {
    			temp.dis=distance(a[temp.index1], a[temp.index2])-a[temp.index2].r;
    			temp.flag=true;
    			que.push(temp);
    		}
    	} else {
    		a[temp.index1].r=a[temp.index2].r=temp.dis;
    		ans+=2*PI*a[temp.index1].r*a[temp.index1].r;
    		a[temp.index1].vis=true;
    		a[temp.index2].vis=true;
    		cnt+=2;
    	}
    }

    printf("%.15f\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值