poj 1873 The Fortified Forest(凸包+枚举)

来源:互联网 发布:时间序列数据下载 编辑:程序博客网 时间:2024/05/16 00:45

【题目大意】:给出n棵树,每棵树有坐标,权值,和长度,现在要砍下其中的某些树,来做围栏来把剩下的树围起来,问损失的数最小价值是多少。


【解题思路】:明显求围栏就是一个凸包问题,由于树最多只有13棵,所以我们可以直接枚举哪些树留下,来求凸包,取最小值即可。。


【代码】:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#include <cmath>#include <string>#include <cctype>#include <map>#include <iomanip>                   using namespace std;                   #define eps 1e-8#define PI acos(-1.0)#define inf 1<<30#define linf 1LL<<60#define pb push_back#define lc(x) (x << 1)#define rc(x) (x << 1 | 1)#define lowbit(x) (x & (-x))#define ll long long#define INF 999999999.9struct Point{    double x, y, dis ,val, len;}tmp[20],pt[20],stack[20],p0;//stack为凸包上的点int top,tot;int n,mask;double len,lens;//计算几何距离double get_dis(double x1, double y1, double x2, double y2){    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}//极角比较, 返回-1: p0p1在p0p2的右侧,返回0:p0,p1,p2共线int Cmp_PolarAngel(struct Point p1, struct Point p2, struct Point pb){    double delta=(p1.x-pb.x)*(p2.y-pb.y)-(p2.x-pb.x)*(p1.y-pb.y);    if (delta<0.0) return 1;    else if (delta==0.0) return 0;    else return -1;}// 判断向量p2p3是否对p1p2构成左旋bool Is_LeftTurn(struct Point p3, struct Point p2, struct Point p1){    int type=Cmp_PolarAngel(p3, p1, p2);    if (type<0) return true;    return false;}//先按极角排,再按距离由小到大排int Cmp(const void*p1, const void*p2){    struct Point*a1=(struct Point*)p1;    struct Point*a2=(struct Point*)p2;    int type=Cmp_PolarAngel(*a1, *a2, p0);    if (type<0) return -1;    else if (type==0){        if (a1->dis<a2->dis) return -1;        else if (a1->dis==a2->dis) return 0;        else return 1;    }    else return 1;}//求凸包void Solve(int n,double len){    int k;    p0.x=p0.y=INF;    for (int i=0; i<n; i++){        if (pt[i].y < p0.y){            p0.y=pt[i].y;            p0.x=pt[i].x;            k=i;        }        else if (pt[i].y==p0.y){            if (pt[i].x<p0.x){                p0.x=pt[i].x;                k=i;            }        }    }    pt[k]=pt[0];    pt[0]=p0;    for (int i=1; i<n; i++)        pt[i].dis=get_dis(pt[i].x,pt[i].y,p0.x,p0.y);    qsort(pt+1, n-1, sizeof(struct Point), Cmp);    //去掉极角相同的点    tot=1;    for (int i=2; i<n; i++)        if (Cmp_PolarAngel(pt[i], pt[i-1], p0))            pt[tot++]=pt[i-1];    pt[tot++]=pt[n-1];    //求凸包    top=1;    stack[0]=pt[0];    stack[1]=pt[1];    for (int i=2; i<tot; i++){        while (top>=1 && Is_LeftTurn(pt[i],stack[top],stack[top-1])==false)            top--;        stack[++top]=pt[i];    }    double ans=0;    double len1=0;    stack[top+1]=stack[0];    for (int i=1; i<=top+1; i++) len1+=get_dis(stack[i-1].x,stack[i-1].y,stack[i].x,stack[i].y);    lens=len1;    }int main(){    int Cas=0;    bool flag=true;    while (~scanf("%d",&n)){        if (flag) flag=false;        else cout << endl;        if (n==0) break;        for (int i=0; i<n; i++) scanf("%lf%lf%lf%lf",&tmp[i].x,&tmp[i].y,&tmp[i].val,&tmp[i].len);        double ans=INF;        double alen;        int mask;        for (int i=0; i<(1<<n); i++){            memset(pt,0,sizeof(pt));            int m=-1;            double len=0.0;            double tmp1=0;            for (int j=0; j<n; j++)                if (i&(1<<j)) m++,pt[m]=tmp[j];                else tmp1+=tmp[j].val,len+=tmp[j].len;            if (m+1>=1) {                Solve(m+1,len);                 if (ans>tmp1 && tmp1!=0 && lens<=len) {alen=len-lens; ans=tmp1; mask=i;}            }        }        Cas++;        cout << "Forest " << Cas <<endl;        cout << "Cut these trees:";        for (int i=0; i<n; i++)             if (!(mask&(1<<i))) printf(" %d",i+1);        cout << endl;        printf("Extra wood: %.2f\n",alen);    }    return 0;}


原创粉丝点击