题意是,给出两个尖形的相连的容器,要求向其中灌水。它们具有日常的物理属性,例如两个容器中水平面高度相同以及水高于容器顶部的时候就会溢出。开始的时候打算直接用几何的计算,求出精确值。后来发现,这样的计算实在是太麻烦了,实现起来有很多细节要注意。于是,后来就想到了用二分的方法,枚举水平面的高度,然后求直线切割容器得到的多边形的面积,因为这个面积会随着水平面的高度具有单调性。注意预先确定好二分的上下界即可。1y~
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 7 using namespace std; 8 9 const double EPS = 1e-10; 10 const double FINF = 1e10; 11 const int N = 1111; 12 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 13 struct Point { 14 double x, y; 15 Point() {} 16 Point(double x, double y) : x(x), y(y) {} 17 bool operator < (Point a) const { return sgn(x - a.x) < 0 || sgn(x - a.x) == 0 && sgn(y - a.y) < 0;} 18 bool operator == (Point a) const { return sgn(x - a.x) == 0 && sgn(y - a.x) == 0;} 19 } ; 20 typedef Point Vec; 21 Vec operator + (Vec a, Vec b) { return Vec(a.x + b.x, a.y + b.y);} 22 Vec operator - (Vec a, Vec b) { return Vec(a.x - b.x, a.y - b.y);} 23 Vec operator * (Vec a, double p) { return Vec(a.x * p, a.y * p);} 24 Vec operator / (Vec a, double p) { return Vec(a.x / p, a.y / p);} 25 26 template<class T> T sqr(T x) { return x * x;} 27 inline double dotDet(Vec a, Vec b) { return a.x * b.x + a.y * b.y;} 28 inline double crossDet(Vec a, Vec b) { return a.x * b.y - a.y * b.x;} 29 inline double dotDet(Point o, Point a, Point b) { return dotDet(a - o, b - o);} 30 inline double crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);} 31 32 double polyArea(Point *pt, int n) { 33 double ret = 0.0; 34 pt[n] = pt[0]; 35 for (int i = 0; i < n; i++) ret += crossDet(Point(0.0, 0.0), pt[i], pt[i + 1]); 36 return fabs(ret) / 2.0; 37 } 38 inline Point lineIntersect(Point P, Vec u, Point Q, Vec v) { return P + u * (crossDet(v, P - Q) / crossDet(u, v));} 39 40 Point gheef[2][N], tmp[N]; 41 double bottom[2]; 42 int n[2]; 43 44 double getArea(double x, int id) { 45 if (x <= bottom[id]) return 0.0; 46 Point s = Point(-FINF, x), t = Point(FINF, x); 47 for (int i = 0; i < n[id]; i++) tmp[i] = gheef[id][i]; 48 int l = 0, r = n[id] - 1; 49 while (crossDet(tmp[l], s, t) * crossDet(tmp[l + 1], s, t) > 0) l++; 50 while (crossDet(tmp[r], s, t) * crossDet(tmp[r - 1], s, t) > 0) r--; 51 tmp[l] = lineIntersect(s, t - s, tmp[l], tmp[l + 1] - tmp[l]); 52 tmp[r] = lineIntersect(s, t - s, tmp[r], tmp[r - 1] - tmp[r]); 53 return polyArea(tmp + l, r - l + 1); 54 } 55 56 double getArea(double x) { 57 double ret = 0.0; 58 for (int i = 0; i < 2; i++) { 59 ret += getArea(x, i); 60 } 61 return ret; 62 } 63 64 double dc2(double x) { 65 // cout << getArea(3.536) << endl; 66 double l = min(bottom[0], bottom[1]), r = min(min(gheef[0][0].y, gheef[1][0].y), min(gheef[0][n[0] - 1].y, gheef[1][n[1] - 1].y)); 67 // cout << l << " l r " << r << endl; 68 while (l + 1e-5 < r) { 69 double m = (l + r) / 2.0; 70 if (getArea(m) > x) r = m; 71 else l = m; 72 } 73 return l; 74 } 75 76 int main() { 77 // freopen("in", "r", stdin); 78 int T; 79 double v; 80 cin >> T; 81 while (T-- && cin >> v) { 82 for (int i = 0; i < 2; i++) { 83 cin >> n[i]; 84 bottom[i] = FINF; 85 for (int j = 0; j < n[i]; j++) { 86 cin >> gheef[i][j].x >> gheef[i][j].y; 87 bottom[i] = min(bottom[i], gheef[i][j].y); 88 } 89 } 90 printf("%.3f ", dc2(v)); 91 } 92 return 0; 93 }
——written by Lyon