给一个共有n个点的凸多边形,求一条将该多边形划分为面积和周长都相等的两部分的直线。
Input
第一行一个正整数n,表示多边形的点数。(n <= 40000) 接下来的n行,第i+1行,每行两个实数xi,yi,表示凸多边形的一个点的坐标,点按照逆时针或顺时针的顺序给出。 其中n,|xi|,|yi|<=40000。
Output
如果存在这样的直线,将这条直线与凸多边形的两个交点的坐标分两行输出。你所求的直线必须与多边形有两个交点,且分多边形的两部分周长或面积相差都不能大于10^-3。 如果不存在,输出"impossible"(不含引号)。
Input示例
4 0 0 3 0 3 3 0 3
Output示例
1 0 2 3
解法:
任选多边形上一点,设周长为C,面积为S, p[x]表示顺时针沿着边走x长度的点,f(x)表示p[x],p[x + C / 2]以及沿途经过的顶点构成的多边形的面积 - S / 2。
则显然f(x) = -f(x + C / 2),由零点存在定理知[x, x + C / 2]中必有一解使函数值为0。二分找零点即可。
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define pli pair<ll, int> 29 #define pil pair<int, ll> 30 #define clr(a, x) memset(a, x, sizeof(a)) 31 32 const double pi = acos(-1.0); 33 const int INF = 0x3f3f3f3f; 34 const int MOD = 1e9 + 7; 35 const double EPS = 1e-9; 36 37 /* 38 #include <ext/pb_ds/assoc_container.hpp> 39 #include <ext/pb_ds/tree_policy.hpp> 40 using namespace __gnu_pbds; 41 #define TREE tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> 42 TREE T; 43 */ 44 45 struct Point { 46 double x, y; 47 Point () {} 48 Point (double x, double y) : x(x), y(y) {} 49 Point operator - (const Point &p) const { 50 return Point(x - p.x, y - p.y); 51 } 52 double operator ^ (const Point &p) const { 53 return x * p.y - y * p.x; 54 } 55 double len() { 56 return sqrt(x * x + y * y); 57 } 58 bool operator == (const Point &p) const { 59 return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS; 60 } 61 void input() { 62 scanf("%lf%lf", &x, &y); 63 } 64 void output() { 65 printf("%.12f %.12f ", x, y); 66 } 67 } p[40015], p1[40015], p2[40015]; 68 Point slice(Point p1, Point p2, double l) { 69 double L = (p2 - p1).len(); 70 if (L < EPS) return p1; 71 return Point(p1.x + (p2.x - p1.x) * l / L, p1.y + (p2.y - p1.y) * l / L); 72 } 73 double L[40015]; 74 double S(Point p[], int n) { 75 double res = 0; 76 for (int i = 0; i < n; ++i) { 77 res += p[i] ^ p[(i + 1) % n]; 78 } 79 return fabs(res); 80 } 81 int n; 82 double totS; 83 double cal(double x) { 84 double sx = x, ex = x + L[n - 1] * 0.5; 85 Point tp[40015]; 86 int index = 0; 87 int id1 = upper_bound(L, L + n, sx) - L; 88 int id2 = upper_bound(L, L + n, ex) - L; 89 if (id1) sx -= L[id1 - 1]; 90 tp[index++] = slice(p[id1], p[(id1 + 1) % n], sx); 91 for (int i = id1 + 1; i <= id2; ++i) { 92 tp[index++] = p[i]; 93 } 94 if (id2) ex -= L[id2 - 1]; 95 tp[index++] = slice(p[id2], p[(id2 + 1) % n], ex); 96 return S(tp, index) - totS * 0.5; 97 } 98 Point get(double x) { 99 int id = upper_bound(L, L + n, x) - L; 100 if (id) x -= L[id - 1]; 101 return slice(p[id], p[(id + 1) % n], x); 102 } 103 int main() { 104 scanf("%d", &n); 105 for (int i = 0; i < n; ++i) { 106 p[i].input(); 107 } 108 totS = 0; 109 for (int i = 0; i < n; ++i) { 110 L[i] = L[i - 1] + (p[(i + 1) % n] - p[i]).len(); 111 } 112 double s = 0, e = L[n - 1] * 0.5, mi; 113 int f = cal(s) > 0; 114 for (int rep = 1; rep <= 70; ++rep) { 115 mi = (s + e) * 0.5; 116 double v = cal(mi); 117 if (fabs(v) < EPS) break; 118 if (f == (v > 0)) { 119 s = mi; 120 } else { 121 e = mi; 122 } 123 } 124 get(mi).output(); 125 get(mi + L[n - 1] * 0.5).output(); 126 return 0; 127 }