• codeforces 606 E. Freelancer's Dreams(凸包)


    传送门:http://codeforces.com/contest/606/problem/E

    解题思路:

      我们可以将所有的$(a_{i},b_{i})$视为二维坐标轴上的点$(x,y)$,对于任意两点$(x_{1},y_{1}),(x_{2},y_{2})$,将这两点连起来,所形成的的线段上任意一点为一天的可以获得的量。

      那么当选取多个点时该如何考虑呢?假设有三个点A,B,C被选到,设D为BC上任意一点,ABC三点可以选取的点必然为AD上一点,不拿看出,这个范围是三角形ABC内部(含边界)。推广到n个点,单日可获得的必然是这n个点所构成的凸包。

      因此任务转化为了凸包内找一个点(x,y),使得$max(p/x,q/y)$最小。假设凸包和$(0,0)$到$(p,q)$的直线有交点,必然是取凸包和直线的交点,求出凸包,然后每一条线都check一下就好了,当然其实最多也只有两条线会相交。若无交点,而必然是凸包的顶点了,枚举一下即可。

      从得出的结论可以看出最多不会取超过两个点,因为必然是某一点,或者某两点连成的直线上的点,队友好像是根据这个性质用的三分做的。

      比赛的时候发现自己凸包的板子写的天花乱坠,既没有类封装,也没有函数封装,打了半天没打出来。

      最后贴上AC代码。

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <double,double> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define all(x) x.begin(),x.end()
    #define pb push_back
    #define fi first
    #define se second
    #define mes(a,b) memset(a,b,sizeof a)
    #define mp make_pair
    #define dd(x) cout<<#x<<"="<<x<<" "
    #define de(x) cout<<#x<<"="<<x<<"
    "
    #define debug() cout<<"I love Miyamizu Mitsuha forever.
    "
    const int inf=0x3f3f3f3f;
    const int maxn=1e5+5;
    pii p[maxn];
    
    
    pii point[maxn];//存放点
    double dis(const pii &s1,const pii &s2)//两点间距离
    {
        return sqrt((s1.fi-s2.fi)*(s1.fi-s2.fi)+(s1.se-s2.se)*(s1.se-s2.se));
    }
    pii operator -(const pii &s1,const pii &s2)
    {
        return mp(s1.fi-s2.fi,s1.se-s2.se);
    }
    double chaji(const pii &s1,const pii &s2)//差积 
    {
        return s1.fi*s2.se-s1.se*s2.fi;
    }
    bool comp(const pii &s1,const pii &s2)
    {
        double x=chaji(s1-point[0],s2-point[0]);
        if( x>0|| (x==0&&fabs(s1.fi-point[0].fi)<fabs(s2.fi-point[0].fi)) ) return 1;
        else return 0;
    }
    
    int graham(pii point[],int n)//计算凸包
    {
        int p=0,cnt=0;
        rep(i,1,n)
            if( point[i].se<point[p].se||(point[i].se==point[p].se&&point[i].fi<point[p].fi) )
                p=i;
        swap(point[0],point[p]);
        sort(point+1,point+n,comp);
        cnt=2;
        rep(i,2,n)
        {
            while(cnt>=2&&chaji( point[cnt-1]-point[i],point[cnt-2]-point[i] )>=0 ) cnt--;
            point[cnt++]=point[i];
        }
        return cnt;
    }
    
    double a,b;
    pii node(pii s1,pii s2)
    {
        double x=( (s1.se*s2.fi-s1.fi*s2.se)/(s2.fi-s1.fi) )/(b/a-(s2.se-s1.se)/(s2.fi-s1.fi));
        double y=b/a*x;
        return mp(x,y);
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n>>a>>b;
        rep(i,0,n) cin>>p[i].fi>>p[i].se;
        if(n==1)
        {
            cout<<fixed<<setprecision(10)<<max(a/p[0].fi,b/p[0].se);
            return 0;
        }
        int cnt=graham(p,n);
        double ans=1e18;
        rep(i,0,cnt-1)
        {
            pii point=node(p[i],p[i+1]);//求交点
            if(point.fi<=p[i].fi&&point.fi>=p[i+1].fi) ans=min(ans,a/point.fi);//判断交点是否在线段上
        }
        rep(i,0,cnt) ans=min(ans,max(a/p[i].fi,b/p[i].se));
        cout<<fixed<<setprecision(10)<<ans<<"
    ";
        return 0;
    }
  • 相关阅读:
    c#中子线程控制进度条的一个简单例子
    c#中WinForm的TextBox循环自动滚动示例
    c#中重定向windows控制台程序的输出信息
    c#中List <int[]>集合添加和查找元素
    LogExplore的一个详细操作手册
    ConsoleApplication也精彩,一个控制台进度条的示例。
    c#通过oledb获取excel文件表结构信息
    Dephi中获取webbrowser选取区域的html代码示例
    SQL2005中利用xml拆分字符串序列
    今天装上了php6```
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/12847029.html
Copyright © 2020-2023  润新知