• The Fortified Forest POJ


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

    题意:传说中WF水题。。。。给你树的每个坐标,价值以及建造长度,要求你砍掉一些树来把其他数都围起来,来求砍掉哪些树和多余的砍掉的木材长度,达到最优价值最少

    思路:用二进制枚举所有砍树的情况(2^n),然后算出没被砍的树的凸包和周长,当砍掉树的建造周长大于等于凸包周长时,记录价值,当下一次价值大于该价值时可以直接跳过不用考虑,每次符合条件更新即可

      1 // 
      2 // Created by HJYL on 2020/2/1.
      3 //
      4 #include<iostream>
      5 #include<cstring>
      6 #include<cstdio>
      7 #include<cmath>
      8 #include<algorithm>
      9 using namespace std;
     10 const double eps=1e-8;
     11 const int maxn=100;
     12 const int INF=0x3ffff;
     13 int dcmp(double x)
     14 {
     15     if(fabs(x)<eps)
     16         return 0;
     17     return x<0?-1:1;
     18 }
     19 struct Point {
     20     double x, y;
     21     int value;
     22     int len;
     23 
     24     Point(double x = 0, double y = 0) : x(x), y(y) {}
     25 
     26     Point operator-(Point const &B) const {
     27         return Point(x - B.x, y - B.y);
     28     }
     29     bool operator<(Point const &C)const{
     30         if(x==C.x)
     31             return y<C.y;
     32         return x<C.x;
     33     }
     34 }initial,p[maxn];
     35 
     36 double Cross(Point A,Point B)
     37 {
     38     return (A.x*B.y)-(A.y*B.x);
     39 }
     40 
     41 double Len(Point A,Point B)
     42 {
     43     return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
     44 }
     45 //极角排序
     46 bool cmp(const Point& A,const Point& B)
     47 {
     48     double t=Cross(A-initial,B-initial);
     49     if(t>0)//叉积大于0,B在A的左边,A在外凸包上
     50         return true;
     51     else if(t<0)
     52         return false;
     53     else
     54         return Len(A,initial)<Len(B,initial);//极角相同采用最近的点
     55 }
     56 int Hull(Point *p,int n,Point *ch) ///**求凸包*/
     57 {
     58     sort(p,p+n);//n顶点数
     59     int m = 0;
     60     for(int i = 0; i < n; i++)
     61     {
     62         while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
     63         ch[m++] = p[i];
     64     }
     65     int k = m;
     66     for(int i = n-2; i >= 0; i--)
     67     {
     68         while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
     69         ch[m++] = p[i];
     70     }
     71     if(n > 1) m--;
     72     return m;
     73 }
     74 
     75 int main()
     76 {
     77     int n;
     78     int cas=1;
     79     while(~scanf("%d",&n)&&n)
     80     {
     81         for(int i=0;i<n;i++)
     82             scanf("%lf%lf%d%d",&p[i].x,&p[i].y,&p[i].value,&p[i].len);
     83         int minv=INF;//最优花费价值价值
     84         int cut=INF;//砍掉树的最优数目
     85         double morel=0;//剩余木材长度
     86         int ops=0;//选择的所有二进制中第几个
     87         for(int i=0;i<(1<<n);i++)//二进制枚举所有情况
     88         {
     89             double ll=0;//选择树的长度和
     90             double vv=0;//选择树的价值和
     91             int pos=0;//没被选的树的数量
     92             Point bb[maxn],ch[maxn*2];//bb记录没被选的,ch用来求凸包顶点集存坐标
     93             int cut1;//该种二进制方法下砍掉树的数量
     94             for(int j=0;j<n;j++)//一种二进制中可选与不可选
     95             {
     96                 if(i&(1<<j))//砍掉该树
     97                 {
     98                     ll+=p[j].len;
     99                     vv+=p[j].value;
    100                 } else//不砍的树
    101                 {
    102                     bb[pos].x=p[j].x;
    103                     bb[pos++].y=p[j].y;//存不砍树的点集接下来求凸包
    104                 }
    105             }
    106             // printf("pos=%d
    ",pos);
    107             if(vv>minv)//这种方法利用的价值大于之前的不可取
    108                 continue;
    109             cut1=n-pos;//砍掉的数目
    110             double zhou=0;
    111             int mm=Hull(bb,pos,ch);//凸包顶点数
    112             // printf("mm=%d
    ",mm);
    113             // printf("ch=
    ");
    114             // for(int kk=0;kk<mm;kk++)
    115             //    printf("ch%d=(%lf,%lf)
    ",kk,ch[kk].x,ch[kk].y);
    116             for(int t=1;t<mm;t++)
    117                 zhou+=Len(ch[t],ch[t-1]);
    118             zhou+=Len(ch[0],ch[mm-1]);//凸包周长
    119             //  printf("zhou=%.2lf
    ",zhou);
    120             if(ll>=zhou)
    121             {
    122                 if(vv<minv||(vv==minv&&cut1<cut))//价值小于之前的或者价值相等但是数目比之前的还要少则更优
    123                 {
    124                     minv=vv;
    125                     cut=cut1;
    126                     morel=ll-zhou;
    127                     ops=i;
    128                 }
    129             }
    130         }
    131         //  printf("ops=%d
    ",ops);
    132         if(cas>1)
    133             printf("
    ");
    134         printf("Forest %d
    ",cas++);
    135         printf("Cut these trees:");
    136         for(int tt=0;tt<n;tt++)
    137             if(ops&(1<<tt))//该种二进制中被砍的树的位置(编号)
    138                 printf(" %d",tt+1);
    139         printf("
    ");
    140         printf("Extra wood: %.2lf
    ",morel);
    141     }
    142     return 0;
    143 }
  • 相关阅读:
    echo "不允许上传该类型的文件
    php构造函数,引入数据库操作类函数
    php函数描述及例子
    php如何判断远程文件是否存在
    多线程面试题系列(16):多线程十大经典案例之一 双线程读写队列数据
    多线程面试题系列(15):关键段,事件,互斥量,信号量的“遗弃”问题
    多线程面试题系列(14):读者写者问题继 读写锁SRWLock
    多线程面试体系列(13):多线程同步内功心法——PV操作下
    多线程面试题系列(12):多线程同步内功心法——PV操作上
    多线程面试题系列(11):读者写者问题
  • 原文地址:https://www.cnblogs.com/Vampire6/p/12250906.html
Copyright © 2020-2023  润新知