POJ 1873 计算几何

思路:

二进制枚举一下要删哪些点

求个凸包,算一下贡献

//By SiriusRen
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define eps 1e-9
int n,cases,top,tot,k,rem,ansrem,ans;
double length,tempdis,wei,answei,remwei;
struct Tree{double x,y,v,l;}tr[25],point[25],tubao[25];
bool operator<(Tree a,Tree b){if(abs(a.x-b.x)<eps)return a.y<b.y;return a.x<b.x;}
double operator*(Tree a,Tree b){return a.x*b.y-a.y*b.x;}
Tree operator-(Tree a,Tree b){Tree c;c.x=a.x-b.x;c.y=a.y-b.y;return c;}
double dis(Tree a){return sqrt(a.x*a.x+a.y*a.y);}
double cross(Tree a,Tree b,Tree c){return (a-c)*(b-c);}
int main(){
    while(scanf("%d",&n)&&n){
        answei=1000000;
        for(int i=0;i<n;i++)scanf("%lf%lf%lf%lf",&tr[i].x,&tr[i].y,&tr[i].v,&tr[i].l);
        for(int i=0;i<(1<<n);i++){
            length=tot=top=rem=tempdis=wei=0;
            for(int j=0;j<n;j++){
                if(i&(1<<j))point[++tot]=tr[j],rem++;
                else length+=tr[j].l,wei+=tr[j].v;
            }
            sort(point+1,point+1+tot);
            for(int j=1;j<=tot;j++){
                while(top>1&&cross(tubao[top],point[j],tubao[top-1])<-eps)top--;
                tubao[++top]=point[j];
            }k=top;
            for(int j=tot-1;j>=1;j--){
                while(top>k&&cross(tubao[top],point[j],tubao[top-1])<-eps)top--;
                tubao[++top]=point[j];
            }
            for(int j=1;j<top;j++)tempdis+=dis(tubao[j]-tubao[j+1]);
            if(tempdis<length){
                if(wei<answei)answei=wei,ansrem=rem,ans=i,remwei=length-tempdis;
                else if(wei==answei&&rem<ansrem)ansrem=rem,ans=i,remwei=length-tempdis;
            }
        }
        printf("Forest %d\nCut these trees:",++cases);
        for(int j=0;j<n;j++)if(!(ans&(1<<j)))printf(" %d",j+1);
        printf("\nExtra wood: %.2lf\n\n",remwei);
    }
}

 

posted @ 2018-07-28 19:14  SiriusRen  阅读(166)  评论(0编辑  收藏  举报