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

来源:互联网 发布:删数问题 贪心算法 编辑:程序博客网 时间:2024/06/04 08:50

测试地址: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-8using 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("\n\n");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\nCut these trees: ",t);for(int i=1;i<=n;i++)  if (ans[i]) printf("%d ",i);printf("\nExtra wood: %.2lf",anslen);  }    return 0;}


0 0