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\n",++u);
        printf("Cut these trees:");
        for(int i=0;i<ans.ve.size();i++)
            cout<<" "<<ans.ve[i];
        cout<<endl;
        printf("Extra wood: %.2lf\n",ans.l);
    }
    return 0;
}

 

posted @ 2020-10-06 12:45  ~zcb  阅读(107)  评论(0编辑  收藏  举报