[三分法初探]

[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;
}

[Codeforces 605C]

首先这是一个线性规划问题,有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
*/

  

posted @ 2016-03-31 21:27  _Horizon  阅读(474)  评论(0编辑  收藏  举报