[三分法初探]
[Uva Error Curves]一些二次函数取max的交集还是一个下凸函数。三分即可
#include <bits/stdc++.h> #define maxn 10010 using namespace std; int n, a[maxn], b[maxn], c[maxn]; #define F(i, x) a[i] * x * x + b[i] * x + c[i] inline double cal(double x){ double ret = -1e12; for(int i = 1; i <= n; i ++) ret = max(ret, F(i, x)); return ret; } inline void solve(){ double l = 0, r = 1000; for(int i = 1; i <= 300; i ++){ double len = (r - l) / 3; double m1 = l + len, m2 = r - len; if(cal(m1) < cal(m2))r = m2; else l = m1; } printf("%.4lf\n", cal(l)); } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d%d%d", &a[i], &b[i], &c[i]); solve(); } return 0; }
[Zoj Light Bulb]列出数学式子,是一个对勾函数(可以直接解),或者三分,注意影子到地上的判断,不过D-x≤H??
#include <bits/stdc++.h> using namespace std; double H, h, D, P, Q; inline double check(double x){ return -x + P / x + Q; } void solve(){ P = D * (h - H), Q = D + H; double l = 1e-9, r = min(H, D); for(int i = 1; i <= 1000; i ++){ double len = (r - l) / 3; double m1 = l + len, m2 = r - len; if(check(m1) > check(m2))r = m2; else l = m1; } printf("%.3lf\n", check(r)); } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%lf%lf%lf", &H, &h, &D); solve(); } return 0; }
[HDU Line belt]三分再三分
#include <bits/stdc++.h> using namespace std; struct Point{ double x, y; inline void read(){scanf("%lf%lf", &x, &y);} }A, B, C, D; #define Sqr(x) (x)*(x) double Len(const Point& a, const Point& b){ return sqrt(Sqr(a.x-b.x) + Sqr(a.y-b.y)); } int P, Q, R; double T(double a, double b){ Point X, Y; X.x = a * (B.x - A.x) + A.x; X.y = a * (B.y - A.y) + A.y; Y.x = b * (C.x - D.x) + D.x; Y.y = b * (C.y - D.y) + D.y; return Len(A, X) / P + Len(D, Y) / Q + Len(X, Y) / R; } double check(double a){ double l = 0, r = 1; while(r - l > 1e-6){ double len = (r - l) / 3.0; double m1 = l + len, m2 = r - len; if(T(a, m1) < T(a, m2))r = m2; else l = m1; }return T(a, r); } int main(){ int test; scanf("%d", &test); while(test --){ A.read(), B.read(), C.read(), D.read(); scanf("%d%d%d", &P, &Q, &R); double l = 0, r = 1; while(r - l > 1e-6){ double len = (r - l) / 3.0; double m1 = l + len, m2 = r - len; if(check(m1) < check(m2))r = m2; else l = m1; } printf("%.2lf\n", check(r)); } return 0; }
[POJ 3301]Texas Trip
如果平行于坐标轴的正方形很好计算
如何计算歪的正方形嘞??
旋转角度嘛。一个关于旋转角度的下凸函数
然后三分角度QAQ orz神
#include <cmath> #include <algorithm> #include <cstdio> #define maxn 100 using namespace std; int n; struct Point{ double x, y; }a[maxn], b[maxn]; #define Sqr(x) x * x double check(){ double lf = 1e12, rg = -1e12; double up = rg, dw = lf; for(int i = 1; i <= n; i ++){ lf = min(lf, a[i].x); rg = max(rg, a[i].x); up = max(up, a[i].y); dw = min(dw, a[i].y); } return Sqr(max(rg - lf, up - dw)); } const double pi = acos(-1.0); double Mdf(double x){ for(int i = 1; i <= n; i ++){ a[i].x = b[i].x * cos(x) - b[i].y * sin(x); a[i].y = b[i].x * sin(x) + b[i].y * cos(x); } return check(); } void solve(){ double l = 0, r = pi; for(int i = 1; i <= 10000; i ++){ double len = (r - l) / 3; double m1 = l + len, m2 = r - len; if(Mdf(m1) < Mdf(m2)) r = m2; else l = m1; } printf("%.2lf\n", Mdf(l)); } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%lf%lf", &b[i].x, &b[i].y); solve(); } return 0; }
首先这是一个线性规划问题,有100000个变元,2个约束条件。0并不是一个初始解,所以对偶一下,100000个约束条件,2个变元。发现并不能线性规划单纯形,考虑一些半平面的交是上凸函数,所以确定y1可以找出y2的值,所以可以三分啦(然而标解是二分+凸包)
#include <bits/stdc++.h> #define maxn 100010 using namespace std; int n, p, q; int a[maxn], b[maxn]; double check(double y){ double ret = 0x7fffffff; for(int i = 1; i <= n; i ++) ret = min(ret, (1.0 - a[i] * y) / b[i]); return q * ret + p * y; } int main(){ scanf("%d%d%d", &n, &p, &q); int x = 0; for(int i = 1; i <= n; i ++){ scanf("%d%d", &a[i], &b[i]); if(a[i] > x) x = a[i]; } double l = 0, r = 1.0 / x; for(int i = 1; i <= 300; i ++){ double len = (r - l) / 3; double m1 = l + len, m2 = r - len; if(check(m1) < check(m2)) l = m1; else r = m2; } printf("%.12lf\n", check(l)); return 0; }
[SDOI 2013]保护出题人
#include <bits/stdc++.h> #define maxn 100010 using namespace std; typedef long long ll; ll n, d; ll a[maxn], x[maxn]; /* 每一关的独立性。 攻击力 = Max((sum[i] - sum[j-1]) / (xi + (i - j) * d)) */ ll sum[maxn]; struct Point{ ll x, y; Point(ll a = 0, ll b = 0):x(a), y(b){} }; double operator * (const Point& a, const Point& b){ return (double)a.x * b.y - (double)a.y * b.x; } Point st[maxn]; Point operator - (const Point &a, const Point &b){ return Point(a.x - b.x, a.y - b.y); } int top; int i; double check(int p){ return (double)(sum[i] - st[p].y) / (x[i] + i * d - st[p].x) ; } int main(){ scanf("%lld%lld", &n, &d); for(int j = 1; j <= n; j ++) scanf("%lld%lld", &a[j], &x[j]); double ans = 0; for(i = 1; i <= n; i ++){ sum[i] = sum[i-1] + a[i]; Point now = Point(i * d, sum[i-1]); while(top > 1 && (st[top] - st[top-1]) * (now - st[top]) <= 0) top --; st[++ top] = now; int l = 1, r = top; while(r - l >= 3){ int m1 = (l + l + r) / 3, m2 = (l + r + r) / 3; if(check(m1) < check(m2)) l = m1; else r = m2; } int mx = l; for(int j = l + 1; j <= r; j ++) if(check(j) > check(mx)) mx = j; l = mx; ans += (double)(sum[i] - st[l].y) / (x[i] + i * d - st[l].x); } printf("%.0lf\n", ans); return 0; } /* Input 5 2 3 3 1 1 10 8 4 8 2 3 Output 7 1≤n≤10^5,1≤d≤10^12,1≤x≤10^12,1≤a≤10^12 */
给时光以生命,而不是给生命以时光。