SGU 114 三分 类似于 HDU 4355(4355 同样也是一个三分的题目)

      好吧,题目大概意思就是找x轴上找到一个点,使得这个点到其他点的距离乘以权值最小,网上的那种做法我还要思考一下。。。这题就先用三分做掉好了

      精度写成了.4f过了,但是.5fWA,。。还是要注意一下。。这个题目和HDU 4355 很像 这里给出4355 的链接  http://acm.hdu.edu.cn/showproblem.php?pid=4355

      这两个题目是一样的。。至少我用的方法是一样的,都可以通过三分来解决。

      三分是用来求解单峰函数的极值的,就拿这个题目的来说,我们可以构造出一个函数F(X)来描述这一点的不满意度,显然F(X)=∑fabs(X-index)*weigh,其中 index表示下标,weigh表示权值,求和便是总的不满意度。其实我们可以单看一项,fabs(X-index)*weigh这个函数在坐标系上是一个凹函数,那么根据有限个凹函数的和仍然是凹函数这个定理我们可以推知F(X)也是凹函数,凹函数是一种单峰函数,因此F(X)是单峰函数,因此这道题目可以用三分法来求解,只是写三分的时候需要注意一下边界的移动情况,不过那都是细节了,下面给出SGU 114 的代码:

    

#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

int n;
double up,down=0x3f3f3f3f,mid1,mid2,dis1,dis2;
struct Node{
    double index,wi;
}arr[15010];

int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;++i)
            scanf("%lf%lf",&arr[i].index,&arr[i].wi),up=max(up,arr[i].index),down=min(down,arr[i].index);

        while(up-down>=1E-5){
            dis1=dis2=0;
            mid1=(up+down)/2,mid2=(mid1+up)/2;
            for(int i=0;i<n;++i)
                dis1+=fabs(mid1-arr[i].index)*arr[i].wi,dis2+=fabs(mid2-arr[i].index)*arr[i].wi;
            (dis1<dis2)?up=mid2:down=mid1;
            //printf("%lf %lf\n",dis1,dis2);
        }
        printf("%.4lf\n",up);up=0,down=0x3f3f3f3f;
    }
    return 0;
}

   接下来是HDU 4355
   这道题目的函数F(X)=∑fabs(X-index)*weigh^3,其实说假若不考虑极值点恰好在端点的情况的时候,是可以求导的,当然了,必须取定X∈(ai,a(i+1))这样的一个开区间里面,然后就可以去掉绝对值符号,求导数就看出来二阶导数是大于0的,然后就可以知道这个函数是凹函数,然后就可以知道这个函数是单峰函数了,代码同上面的差不多
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<climits>


using namespace std;

int t,n,times=1;
double s[50010],w[50010],mid1,mid2,te1,te2,up,down,ans=1E+200,maxm,minm=1E+200;

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;++i)
            scanf("%lf%lf",&s[i],&w[i]),maxm=max(maxm,s[i]),minm=min(minm,s[i]);
        up=maxm,down=minm;
        while(up-down>=1E-5){
            te1=te2=0;
            mid1=(up+down)/2;
            mid2=(mid1+up)/2;
            for(int i=0;i<n;++i){
                te1+=pow(fabs(mid1-s[i]),3)*w[i],te2+=pow(fabs(mid2-s[i]),3)*w[i];
            }
            if(te1>ans&&te2>ans){
                down=mid1,up=mid2;
            }
            else if(te1>te2){
                ans=min(te2,ans);
                down=mid1;
            }
            else{
                ans=min(te1,ans);
                up=mid2;
            }
        }
        printf("Case #%d: %d\n",times,(long long)floor(ans+0.5));ans=1E+200;++times;maxm=0,minm=1E+200;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值