Time Limit: 3000MS | 64bit IO Format: %lld & %llu |
題意:
給平面上n個點,找一條直線,使得所有點在直線同側(或直線上),且到直線距離之和儘量小。
分析:
O(n)時間遍歷凸包的n條邊,計算每條邊對應的總距離,比較哪一個最小。
計算總距離可通過點到直線的距離公式,計算所有點的x座標與y座標之和,O(1)的計算出總距離。
改了一下模板,統一了一下。
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const long long N=10005;
const long long mod=1e9;
const double eps=1e-10;
const double PI=acos(-1.0);
typedef long long ll;
struct Point {
double x,y;
Point (double x=0, double y=0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y);}
Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y);}
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p);}
Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p);}
bool operator < (const Point &a, const Point &b) {
return a.x<b.x|| (a.x==b.x && a.y<b.y);
}
int dcmp(double x) {
if (fabs(x)<eps) {
return 0;
} else {
return x<0? -1:1;
}
}
bool operator == (const Point& a, const Point &b) {
return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
//點積 長度與夾角
double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y;}
double Length(Vector A) { return sqrt(Dot(A, A));}
double Angle(Vector A, Vector B) {return acos(Dot(A, B)/Length(A)/Length(B));}
//叉積
double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x;}
double Area2(Point A, Point B, Point C) { return Cross(B-A, C-A);}
//rad是弧度
Vector Rotate(Vector A, double rad) {
return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
//計算向量的單位法線,調用前確保A不是零向量
Vector Normal(Vector A) {
double L=Length(A);
return Vector(-A.y/L, A.x/L);
}
//直線交點,確保P+tv和Q+tw有唯一交點。當且僅當Cross(v,w)非0
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) {
Vector u=P-Q;
double t=Cross(w, u)/Cross(v, w);
return P+v*t;
}
//點到直線距離
double DistanceToLine(Point P, Point A, Point B) {
Vector v1=B-A,v2=P-A;
return fabs(Cross(v1, v2))/Length(v1);
}
//點到線段距離
double DistanceToSegment(Point P, Point A, Point B) {
if (A==B) return Length(P-A);
Vector v1=B-A, v2=P-A,v3=P-B;
if (dcmp(Dot(v1, v2))<0) return Length(v2);
else if (dcmp(Dot(v1, v3))>0) return Length(v3);
else return fabs(Cross(v1, v2)) / Length(v1);
}
//計算點在線段上的投影
Point GetLineProjection(Point P, Point A, Point B) {
Vector v=B-A;
return A+v*(Dot(v, P-A)/Dot(v, v));
}
//線段相交判定(不計算端點)
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2) {
double c1=Cross(a2-a1, b1-a1), c2=Cross(a2-a1, b2-a1),
c3=Cross(b2-b1, a1-b1), c4=Cross(b2-b1, a2-b1);
return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
//計算端點是否在另外一條線段上
bool OnSegment(Point p, Point a1, Point a2) {
return dcmp(Cross(a1-p, a2-p))==0 &&dcmp(Dot(a1-p, a2-p))<0;
}
//計算凸多邊形面積
double ConvexPolyonArea(Point* p,int n) {
double area=0;
for (int i=1; i<n-1; i++) {
area+=Cross(p[i]-p[0], p[i+1]-p[0]);
}
return area/2;
}
//計算多邊形有向面積
double PolygonArea(Point *p,int n) {
double area=0;
for (int i=1; i<n-1; i++) {
area+=Cross(p[i]-p[0], p[i+1]-p[0]);
}
return area/2;
}
//計算凸包 P272
int ConvexHull(Point *p, int n, Point* ch) {
sort(p, p+n);
int m=0;
for (int i=0; i<n; i++) {
while (m>1&&Cross(ch[m-1] - ch[m-2],p[i]-ch[m-2])<=0) {
m--;
}
ch[m++]=p[i];
}
int k=m;
for (int i=n-2; i>=0; i--) {
while (m>k&&Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])<=0) {
m--;
}
ch[m++]=p[i];
}
if (n>1) {
m--;
}
return m;
}
double torad(double deg) {
return deg/180 *acos(-1);
}
// 過兩點p1, p2的直線一般方程ax+by+c=0
// (x2-x1)(y-y1) = (y2-y1)(x-x1)
void getLineGeneralEquation(const Point& p1, const Point& p2, double& a, double& b, double &c) {
a = p2.y-p1.y;
b = p1.x-p2.x;
c = -a*p1.x - b*p1.y;
}
int main() {
int T,kase=0;
double x[N],y[N];
Point P[N],ch[N];
cin>>T;
while (T--) {
kase++;
int n,pc=0;
double sx,sy;
sx=sy=0;
cin>>n;
for (int i=0; i<n; i++) {
scanf("%lf%lf",&x[i],&y[i]);
P[pc++]=Point(x[i],y[i]);
sx+=x[i];
sy+=y[i];
}
sort(P, P+n);
int m=unique(P, P+n)-P;
m=ConvexHull(P, m, ch);
double ans=1e9;
if (m<=2) {
ans=0;
} else {
for (int i=0; i<m; i++) {
double a,b,c;
getLineGeneralEquation(ch[i], ch[(i+1)%m], a, b, c);
ans=min(ans,fabs(a*sx+b*sy+c*n)/sqrt(a*a+b*b));
}
}
printf("Case #%d: %.3lf\n",kase,ans/n);
}
return 0;
}