D.Country Meow 最小球覆盖 三分套三分套三分 && 模拟退火
// 2019.10.3
// 练习题:2018 ICPC 南京现场赛
D Country Meow
题目大意
给定空间内 N 个点,求某个点到 N 个点的距离最大值的最小值。
 
思路
非常裸的最小球覆盖问题啊,即找到半径最小的球包含全部的点。
在最小圆覆盖问题上,可以使用随机增量法,这里没有四点确定球心的公式,所以板子失效了。
最小圆覆盖可以用三分套三分,这里空间有三维,假装证明得到在任意一维上都满足凸函数特性,那么再套一层维度三分就OK了。
 
AC代码
三分套三分套三分写法,复杂度O(n*log^3)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps = 1e-3;
struct Point {
	double x, y, z;
	Point() {
		x = y = z = 0.0;
	}
	Point(double xx, double yy, double zz) {
		x = xx, y = yy, z = zz;
	}
	Point operator-(const Point& p) {
		return Point(x-p.x, y-p.y, z-p.z);
	}
	double dis() {
		return sqrt(x*x+y*y+z*z);
	}
}pt[110];
int n;
double cal(double x, double y, double z) {
	double res = 0;
	for(int i=1;i<=n;i++) {
		res = max(res, (pt[i]-Point(x, y, z)).dis());
	}
	return res;
}
double cal2(double x, double y) {
	double res = 1e18;
	double l = -100000, r = 100000;
	while(r-l>eps) {
		double m1 = (r-l)/3 + l;
		double m2 = (r-l)/3*2 + l;
		double res1 = cal(x, y, m1), res2 = cal(x, y, m2);
		res = min(res, min(res1, res2));
		if(res1<res2) r = m2;
		else l = m1;
	}
	return res;
}
double cal3(double x) {
	double res = 1e18;
	double l = -100000, r = 100000;
	while(r-l>eps) {
		double m1 = (r-l)/3 + l;
		double m2 = (r-l)/3*2 + l;
		double res1 = cal2(x, m1), res2 = cal2(x, m2);
		res = min(res, min(res1, res2));
		if(res1<res2) r = m2;
		else l = m1;
	}
	return res;
}
int main() {
	cin>>n;
	for(int i=1;i<=n;i++) {
		scanf("%lf %lf %lf", &pt[i].x, &pt[i].y, &pt[i].z);
	}
	double res = 1e18;
	double l = -100000, r = 100000;
	while(r-l>eps) {
		double m1 = (r-l)/3 + l;
		double m2 = (r-l)/3*2 + l;
		double res1 = cal3(m1), res2 = cal3(m2);
		res = min(res, min(res1, res2));
		if(res1<res2) r = m2;
		else l = m1;
	}
	printf("%.10lf\n", res);
	return 0;
}
 
模拟退火写法,对于三维复杂度更低:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps = 1e-5;
struct Point{
    double x, y, z;
}p[110], op;
int n;
inline double dist(Point &a, Point &b) {
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
void solve() {
    double ans, delta = 10000.0;
    double maxDis, tempDis;
    while(delta>eps){
        int id = 0;
        maxDis = dist(op, p[id]);
        for(int i=1;i<n;i++){
            tempDis=dist(op,p[i]);
            if(tempDis>maxDis){
                maxDis = tempDis;
                id = i;
            }
        }
        ans = maxDis;
        op.x += (p[id].x-op.x)/maxDis*delta;
        op.y += (p[id].y-op.y)/maxDis*delta;
        op.z += (p[id].z-op.z)/maxDis*delta;
        delta *= 0.98;
    }
    printf("%.10lf\n", ans);
}
int main() {
    while(scanf("%d", &n)!=EOF && n) {
        op.x = op.y = op.z = 0;
        for(int i=0;i<n;i++) {
            scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);
        }
        solve();
    }
    return 0;
}
POJ2069 Super Star
这一题三分做法会T,只能用模拟退火才能过。
注意初始点选择。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps = 1e-5;
struct Point{
    double x, y, z;
}p[35], op;
int n;
inline double dist(Point &a, Point &b) {
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
void solve() {
    double ans, delta = 100.0;
    double maxDis, tempDis;
    while(delta>eps){
        int id = 0;
        maxDis = dist(op, p[id]);
        for(int i=1;i<n;i++){
            tempDis=dist(op,p[i]);
            if(tempDis>maxDis){
                maxDis = tempDis;
                id = i;
            }
        }
        ans = maxDis;
        op.x += (p[id].x-op.x)/maxDis*delta;
        op.y += (p[id].y-op.y)/maxDis*delta;
        op.z += (p[id].z-op.z)/maxDis*delta;
        delta *= 0.98;
    }
    printf("%.5lf\n", ans);
}
int main() {
    while(scanf("%d", &n)!=EOF && n) {
        op.x = op.y = op.z = 0;
        for(int i=0;i<n;i++) {
            scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);
            op.x += p[i].x;
            op.y += p[i].y;
            op.z += p[i].z;
        }
        op.x /= n; op.y /= n; op.z /= n;
        solve();
    }
    return 0;
}
HDU3007   HDU3932 类似。
注意HDU3932 n==1采用模拟退火要特判。。。。
D.Country Meow 最小球覆盖 三分套三分套三分 && 模拟退火的更多相关文章
- Gym - 101981D The 2018 ICPC Asia Nanjing Regional Contest D.Country Meow 最小球覆盖
		
题面 题意:给你100个三维空间里的点,让你求一个点,使得他到所有点距离最大的值最小,也就是让你找一个最小的球覆盖掉这n个点 题解:红书模板题,这题也因为数据小,精度也不高,所以也可以用随机算法,模拟 ...
 - 最小球覆盖——模拟退火&&三分套三分套三分
		
题目 给出 $N(1 \leq N \leq 100)$ 个点的坐标 $x_i,y_i,z_i$($-100000 \leq x_i,y_i,z_i \leq 100000$),求包围全部点的最小的球 ...
 - Gym101981D - 2018ACM-ICPC南京现场赛D题 Country Meow
		
2018ACM-ICPC南京现场赛D题-Country Meow Problem D. Country Meow Input file: standard input Output file: sta ...
 - 2018ICPC南京D. Country Meow
		
题目: 题意:三维里有n个点,找一个最小的球将所有点覆盖. 题解:退火法模拟的一道板子题. 1 #include <stdio.h> 2 #include <iostream> ...
 - Super Star(最小球覆盖)
		
Super Star http://poj.org/problem?id=2069 Time Limit: 1000MS Memory Limit: 65536K Total Submission ...
 - Country Meow
		
Country Meow 和这基本一样 https://www.cnblogs.com/Fighting-sh/p/9809518.html #include<iostream> #inc ...
 - POJ 最小球覆盖 模拟退火
		
最小球覆盖:用半径最小的球去覆盖所有点. 纯粹的退火算法,是搞不定的,精度不够,不然就会TLE,根本跑不出答案来. 任取一点为球心,然后一点点靠近最远点.其实这才是最主要的. 因为:4个点确定一个球, ...
 - Gym - 101981D Country Meow(模拟退火)
		
题意 三维空间有\(n\)个点,找到另外一个点,离所有点的最大距离最小.求这个距离. 题解 \(1\).最小球覆盖,要找的点为球心. \(2\).模拟退火. 还是补一下模拟退火的介绍吧. 模拟退火有一 ...
 - POJ2069 最小球覆盖 几何法和退火法
		
对这种问题不熟悉的读者 可以先去看一看最小圆覆盖的问题 ZOJ1450 现在我们来看最小球覆盖问题POJ2069 题目很裸,给30个点 求能覆盖所有点的最小球的半径. 先给出以下几个事实: 1.对于一 ...
 
随机推荐
- DELPHI常用类型及定义单元
			
Controls Application (the variable not a type) Forms Beep SysUtils or Windows (different functions) ...
 - php开发面试题---php高级程序员需要掌握的一些知识
			
php开发面试题---php高级程序员需要掌握的一些知识 一.总结 一句话总结: 还是需要多多接触架构师的知识,比如这里说的微服务,还有需要php服务端的知识来解决web端的不足,比如Swoole 1 ...
 - RobotFramework 切换窗口控制的用法小结
			
一:滚动条控制 应用场景:通过滚动条的上下,左右移动,才能让定位的元素可见.
 - C/S模式简单socket通信
			
TCP连接方式 sever.c #include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#inclu ...
 - Java-Class-@I:io.swagger.annotation.ApiOperation
			
ylbtech-Java-Class-@I:io.swagger.annotation.ApiOperation 1.返回顶部 2.返回顶部 1. package com.ylbtech.api. ...
 - JAVA的IO流下载音乐
			
public class DownloadMusic { private static int count = 1; public static void main(String[] args) th ...
 - python redis demo
			
上代码,redis-demo #!/usr/bin/env python #_*_ coding:UTF-8 _*_ import redis ####配置参数 host = '192.168.0.1 ...
 - 4、通过uiautomatorviewer实现appium元素定位
			
熟悉selenium自动化的小伙伴应该知道WebDriver 提供了八种元素定位方法: idnameclass nametag namelink textpartial link textxpathc ...
 - C++ 操作json文件
			
一.环境搭建: 参考文章:https://blog.csdn.net/fakine/article/details/79272090 二.创建实例: #include <stdio.h> ...
 - Java各版本的含义
			
JavaSE(Java Standard Edition):标准版,定位在个人计算机上的应用.这个版本是Java平台的核心,它提供了非常丰富的API来开发一般个人计算机上的应用程序,包括用户界面接口A ...