• 【POJ1873】The Fortified Forest-凸包+枚举方案


    测试地址:The Fortified Forest

    题目大意:有N(2≤N≤15)棵树,每棵树有一个坐标(xi,yi),价值vi,长度li,要砍掉一些树建成围栏防护其他的树,求一个使砍掉的树的价值之和最小的方案,如果有多个方案满足条件,求砍掉的树最少的,输出这种方案中要砍的树的编号,顺便还要输出这种方案下建成围栏之后多余的木材长度。

    做法:考虑到N很小,所以我们就枚举方案求最佳方案就可以了。要防护一些树就要把这些树包围起来,而且使得该封闭图形的周长最小,那么显然就是求凸包了,可以用Graham-Scan算法。一个方案合法当且仅当砍掉的树的长度和大于等于围栏的最小长度,在方案合法的基础上求最优方案即可。注意剩下的树为1棵或2棵的情况(只剩1棵树围栏长度为0,剩2棵树围栏长度为两棵树之间距离的两倍),以及C++和G++保留小数的细微不同(C++下用%.2lf,G++下用%.2f),否则会WA到死(像我一样)。

    以下是本人代码(话说我的代码风格越来越丑了......):

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #define inf 1000000000
    #define eps 1e-8
    using namespace std;
    int n,tot,anstot=inf,ansval=inf,totval,v[20];
    double x[20],y[20],l[20],totlen,anslen,dis;
    bool choice[20]={0},ans[20]={0};
    struct point {double x,y;} p[20];
    
    double multi(point a,point b,point c)
    {
      return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
    }
    
    double dist(point a,point b)
    {
      return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    bool equal(double a,double b)
    {
      if (fabs(a-b)<=eps) return 1;
      else return 0;
    }
    
    bool cmp(point a,point b)
    {
      double s=multi(a,b,p[1]);
      if (!equal(s,0)) return s>0;
      else return dist(p[1],a)<dist(p[1],b);
    }
    
    double graham_scan()
    {
      for(int i=1;i<=tot;i++)
        if (p[i].x<p[1].x||(equal(p[i].x,p[1].x)&&p[i].y<p[1].y))
    	{
    	  swap(p[i].x,p[1].x);
    	  swap(p[i].y,p[1].y);
        }
      
      sort(p+2,p+tot+1,cmp);
      
      int st[20],top=2;
      st[1]=1,st[2]=2;
      for(int i=3;i<=tot;i++)
      {
        double s=multi(p[st[top]],p[i],p[st[top-1]]);
        while(s<0&&!equal(s,0)&&top>1)
    	{
    	  top--;
    	  s=multi(p[st[top]],p[i],p[st[top-1]]);
    	}
    	st[++top]=i;
      }
      
      double len=0;
      for(int i=2;i<=top;i++)
        len+=dist(p[st[i]],p[st[i-1]]);
      len+=dist(p[st[top]],p[st[1]]);
      return len;
    }
    
    void solve()
    {
      tot=totval=0;totlen=0;
      for(int i=1;i<=n;i++)
      {
        if (choice[i])
    	{
    	  totval+=v[i];
    	  totlen+=l[i];
    	}
        else
    	{
    	  p[++tot].x=x[i],p[tot].y=y[i];
    	}
      }
      if (totval>ansval) return;
      if (totval==ansval&&n-tot>=anstot) return; 
      
      if (tot==1) dis=0;
      else dis=graham_scan();
      
      if (totlen<dis&&!equal(totlen,dis)) return;
      ansval=totval,anstot=n-tot,anslen=totlen-dis;
      for(int i=1;i<=n;i++)
        ans[i]=choice[i];
    }
    
    int main()
    {
      int t=0;
      while(scanf("%d",&n)&&n)
      {
        ++t;
    	if (t>1) printf("
    
    ");
    	anstot=inf,ansval=inf;
    	for(int i=1;i<=n;i++)
    	  scanf("%lf%lf%d%lf",&x[i],&y[i],&v[i],&l[i]);
    	
    	for(int i=1;i<(1<<n);i++)
    	{
    	  int x=i;
    	  for(int j=1;j<=n;j++)
    	    choice[j]=x&1,x>>=1;
    	  solve();
    	}
    	
    	printf("Forest %d
    Cut these trees: ",t);
    	for(int i=1;i<=n;i++)
    	  if (ans[i]) printf("%d ",i);
    	printf("
    Extra wood: %.2lf",anslen);
      }
      
      return 0;
    }
    


  • 相关阅读:
    JS 寻路算法
    Fireworks基本使用
    html基础知识汇总(二)之Emmet语法
    JS函数式编程
    Web前端导航
    CSS样式一
    选择器的分类
    框架集
    表单标签元素
    图像热点&图像映射
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793750.html
Copyright © 2020-2023  润新知