poj1873(二进制枚举+求凸包周长)
Posted frankchen831x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1873(二进制枚举+求凸包周长)相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/problem/POJ-1873
题意:n个点(2<=n<=15),给出n个点的坐标(x,y)、价值v、做篱笆时的长度l,求选择哪些点来做篱笆围住另一些点,使得选出的这些点的价值和最小,如果价值和相等要求个数最小。
思路:
看来这是WF的签到题吧。数据很小,直接二进制枚举 (1<<n),然后对未选出的点求凸包的周长,仅当选出点的长度l的和>=凸包周长时才更新答案。
AC code:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=20; const int inf=0x3f3f3f3f; struct Point{ int x,y; Point():x(0),y(0){} Point(int x,int y):x(x),y(y){} }; int n,cas,val,num,res[maxn],v[maxn],l[maxn],vis[maxn]; double ext; int top,stack[maxn]; Point pt[maxn],list[maxn]; int cross(Point p0,Point p1,Point p2){ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } double dis(Point p1,Point p2){ return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(Point p1,Point p2){ int tmp=cross(list[0],p1,p2); if(tmp>0) return true; else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true; else return false; } void init(int m){ Point p0=list[0]; int k=0; for(int i=1;i<m;++i){ if((p0.y>list[i].y)||((p0.y==list[i].y)&&(p0.x>list[i].x))){ p0=list[i]; k=i; } } list[k]=list[0]; list[0]=p0; sort(list+1,list+m,cmp); } double graham(int m){ if(m==1){ top=0; stack[0]=0; } else{ top=1; stack[0]=0; stack[1]=1; for(int i=2;i<m;++i){ while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) --top; stack[++top]=i; } } double ret=0; for(int i=0;i<top;++i) ret+=dis(list[stack[i]],list[stack[i+1]]); ret+=dis(list[stack[top]],list[stack[0]]); return ret; } int main(){ while(scanf("%d",&n),n){ val=num=inf; for(int i=0;i<n;++i) scanf("%d%d%d%d",&pt[i].x,&pt[i].y,&v[i],&l[i]); for(int i=1;i<(1<<n)-1;++i){ int t1=0,t2=0,cnt=0; for(int j=0;j<n;++j){ if((i>>j)&1){ t1+=v[j],t2+=l[j]; } else{ list[cnt++]=pt[j]; } } init(cnt); int cnt2=n-cnt; if((t1<val)||((t1==val)&&(cnt2<num))){ double tmp=graham(cnt); if(tmp>t2) continue; val=t1,num=cnt2,ext=t2-tmp; int t=0; for(int j=0;j<n;++j){ if((i>>j)&1) res[t++]=j; } } } printf("Forest %d Cut these trees:",++cas); for(int i=0;i<num;++i) printf(" %d",res[i]+1); printf(" Extra wood: %.2f ",ext); } return 0; }
以上是关于poj1873(二进制枚举+求凸包周长)的主要内容,如果未能解决你的问题,请参考以下文章
Uva5211/POJ1873 The Fortified Forest 凸包