HDU 4355 Party All the Time (三分求极值)

题意:给定x轴上有n个点,每一个点都有一个权值,让在x轴上选一个点,求出各点到这个点的距离的三次方乘以权值最小。

析:首先一开始我根本不会三分,也并没有看出来这是一个三分的题目的,学长说这是一个三分的题,我就百度了一下什么是三分算法,一看感觉和二分差不多,当然就是和二分差不多,也是慢慢缩短范围。

这个题也这样,在最左端和最右端不断的三分,直到逼进那个点,刚开始我设置的误差eps是10负8,但是TLE了,我以为是太小,三分数太多,然后我又改成10负6还是TLE,我又失望了,干脆我不用误差了,我让它三分200次就结束,但一直是TLE,直到我改到20次,才AC。但实际并不是我设置的太小,而是我用了pow这个函数和fabs这个函数,这两个函数运行起来太慢了,导致我TLEn次,所以我不建议用这两个函数,完全可以自己写嘛,这样才会更快。

知道三分,这个题就很简单了,就是扫一下而已。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <string>
#include <vector>

using namespace std;
typedef long long LL;
const int maxn = 50005;
const double eps = 1E-6;
double x[maxn], w[maxn];
int n;

double f(double mid){
    double ans = 0.0;
    for(int i = 0; i < n; ++i)
        ans += pow(fabs(x[i] - mid), 3) * w[i];
    return ans;

}
int main(){
    int T, cases = 0;  cin >> T;
    while(T--){
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
            scanf("%lf %lf", &x[i], &w[i]);

        double r = x[n-1], l = x[0];
        for(int i = 0; i < 30; ++i){
            double mid_l = l + (r-l) / 3.0;
            double mid_r = r - (r-l) / 3.0;
            if(f(mid_l) < f(mid_r))  r = mid_r;
            else l = mid_l;
        }

        int ans1 = (int)floor(f(l)+0.5), ans2 = (int)floor(f(r)+0.5);
        int ans = min(ans1, ans2);
        printf("Case #%d: %d
", ++cases, ans);
    }
    return 0;
}

这是我不用pow函数的代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <string>
#include <vector>

using namespace std;
typedef long long LL;
const int maxn = 50005;
const double eps = 1E-8;
double x[maxn], w[maxn];
int n;

double f(double mid){
    double ans = 0.0;
    for(int i = 0; i < n; ++i){
        double tmp = x[i] - mid;
        if (tmp < 0)tmp = -tmp;
        ans += tmp*tmp*tmp* w[i];

    }
    return ans;

}
int main(){
    int T, cases = 0;  cin >> T;
    while(T--){
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
            scanf("%lf %lf", &x[i], &w[i]);

        double r = x[n-1], l = x[0];
        while(r - l > eps){
            double mid_l = l + (r-l) / 3.0;
            double mid_r = r - (r-l) / 3.0;
            if(f(mid_l) < f(mid_r))  r = mid_r;
            else l = mid_l;
        }

        int ans1 = (int)floor(f(l)+0.5), ans2 = (int)floor(f(r)+0.5);
        int ans = min(ans1, ans2);
        printf("Case #%d: %d
", ++cases, ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/dwtfukgv/p/5528785.html