• The Fortified Forest


    题目链接:https://vjudge.net/problem/POJ-1873

    题意:有n棵树,每棵树有坐标(x,y),价值v,长度l,问如何砍能砍掉最小价值为的树(价值相同则砍最少的树),能把其他树都围起来。

    思路:由于n特别小,可以枚举砍掉的树,看是否可以围起剩下的树,每次枚举后求一个凸包的周长,看是否满足即可。我用的是dfs枚举,感觉用2进制枚举更好些。

    #include<bits/stdc++.h>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int N;
    struct point
    {
        double x,y;
        double v,l;
        point friend operator -(point a,point b)
        {
            return {a.x-b.x,a.y-b.y,a.v-b.v,a.l-b.l};
        }
    }p[100005],s[100005],q[100005];
    int w[100005];
    struct node
    {
        int v,shu;
        double l;
        vector<int> ve;
    } ans;
    double dis(point a,point b)
    {
        point c=a-b;
        return sqrt(c.x*c.x+c.y*c.y);
    }
    double X(point a,point b)
    {
        return a.x*b.y-a.y*b.x;
    }
    int cmp(point a,point b)
    {
        double x=X(a-p[1],b-p[1]);
    
        if(x>0)
            return 1;
        if(x==0&&dis(a,p[1])<dis(b,p[1]))
            return 1;
        return 0;
    }
    double multi(point p1,point p2,point p3)
    {
        return X(p2-p1,p3-p1);
    }
    void zc(double v,double l,int h)
    {
        ans.v=v;
        ans.shu=h;
        ans.l=l;
        ans.ve.clear();
        for(int i=1;i<=h;i++)
            ans.ve.push_back(w[i]);
    }
    void fun(double l,double v,int n,int h)
    {
        if(n<=1)
        {
            if(v<ans.v||(v==ans.v&&h<ans.shu))
                zc(v,l,h);
            return;
        }
        if(n==2)
        {
            double sum=2*dis(p[1],p[2]);
            if(l-sum>=0.00000001&&(v<ans.v||(v==ans.v&&h<ans.shu)))
                zc(v,l-sum,h);
            return;
        }
        int k=1;
        for(int i=2; i<=n; i++)
            if(p[i].y<p[k].y||(p[i].y==p[k].y&&p[i].x<p[k].x))
                k=i;
        swap(p[1],p[k]);
    
        sort(p+2,p+1+n,cmp);
    
        s[1]=p[1];
        s[2]=p[2];
        int t=2;
        for(int i=3; i<=n; i++)
        {
            while(t>=2&&multi(s[t-1],s[t],p[i])<=0)
                t--;
            s[++t]=p[i];
        }
        double sum=0;
        for(int i=1; i<t; i++)
        {
            sum+=dis(s[i],s[i+1]);
        }
        sum+=dis(s[1],s[t]);
        if(l-sum>=0.00000001&&(v<ans.v||(v==ans.v&&h<ans.shu)))
            zc(v,l-sum,h);
    }
    void dfs(int len,double l,double v,int k,int h)
    {
        if(len==N+1)
        {
            fun(l,v,k,h);
            return;
        }
        w[h+1]=len;
        dfs(len+1,l+q[len].l,v+q[len].v,k,h+1);
    
        p[k+1]=q[len];
        dfs(len+1,l,v,k+1,h);
    }
    int main()
    {
        int u=0;
        while(scanf("%d",&N))
        {
            if(N==0)
                break;
            if(u>0)
                cout<<endl;
            ans.v=30000005;
            for(int i=1; i<=N; i++)
                cin>>q[i].x>>q[i].y>>q[i].v>>q[i].l;
    
            dfs(1,0,0,0,0);
    
            printf("Forest %d
    ",++u);
            printf("Cut these trees:");
            for(int i=0;i<ans.ve.size();i++)
                cout<<" "<<ans.ve[i];
            cout<<endl;
            printf("Extra wood: %.2lf
    ",ans.l);
        }
        return 0;
    }
  • 相关阅读:
    以后面试官再问你三次握手和四次挥手,直接把这一篇文章丢给他
    聊聊面试中常问的GC机制
    四面快手、终拿Offer,想告诉你的一些事情
    深入浅出14个Java并发容器
    Dubbo 在 K8s 下的思考
    一文带你深入浅出Spring 事务原理
    如何高效选择一款消息队列?
    当面试官要你介绍一下MQ时,该怎么回答?
    淘宝双11促销背后采用什么架构技术来实现网站的负载均衡
    Android 更改按钮样式 Button Styles
  • 原文地址:https://www.cnblogs.com/zcb123456789/p/13773148.html
Copyright © 2020-2023  润新知