您的位置:首页 > 其它

poj 1873 The Fortified Forest 凸包+位运算枚举 world final 水题

2014-06-26 15:07 295 查看
题目来源:
http://poj.org/problem?id=1873
题意:给出n棵树的坐标,树的高度和树的价值,从这些树中砍掉一些(整棵整棵的)做围栏把剩余的树围起来,使得消耗的树的价值最小。输出应砍掉哪里些树以及剩余的材料的长度。(如果砍掉的价值相同,则取砍掉数目少的)(2 <= n <= 15)。

1:因为只有15棵树,用位运算枚举砍树情况就行了。

2:枚举时注意剪枝 

3:当剩下的点集处理凸包时m<=1 时特殊处理下

代码如下:

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <stack>
#include <string>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>
using namespace std ;
typedef long long LL;
const int inf=0x7fffffff;
const int N = 20;
double EPS= 1e-10;
double add(double a, double b)
{
if( fabs(a+b)< EPS * ( fabs(a)+fabs(b) ) )  return 0;
return a+b;
}
struct Point{
double x,y;
int v,l;
double dist(Point p){
return sqrt( add( ( x-p.x)*(x-p.x) , (y-p.y)*(y-p.y) ) );
}
};
// pop1*p0p2 > 0 左转
double xmult(Point p1, Point p2, Point p0){
return add( (p1.x-p0.x)*(p2.y-p0.y), -(p1.y-p0.y)*(p2.x-p0.x) );
}
Point List
; // 点集
int top;  // 栈顶指针
Point qs
;
Point p
;
bool operator<(Point a, Point b) // 按y轴值从小到大, y轴值相同时,x轴从小到大排列
{
if(a.y != b.y) return a.y< b.y;
else  return a.x < b.x;
}
// 这种基于平面扫描法的graham扫描算法中, qs中存储的是起点然后回到起点qs[0]=qs[top]=起点
double graham(int n)
{
sort(List,List+n);
double sum=0;
if(n==0 || n==1) return 0;  // 特殊处理下
qs[0]=List[0];
qs[1]=List[1];
top=1;
//构造凸包的下侧
for(int i=2; i<n;i++){
while(top>=1 && xmult( qs[top],List[i],qs[top-1] )<=0 )
top--;
qs[++top]=List[i];
}
//构造凸包的上侧
qs[++top]=List[n-2];
int len=top;
for(int i=n-3 ;i>=0 ; i--){
while(top>=len &&  xmult( qs[top],List[i],qs[top-1] )<=0 )
top--;
qs[++top]=List[i];
}
for(int i=0 ; i<top ; i++)
sum+=qs[i].dist(qs[i+1]);
return sum;
}
// 二进制枚举
void solve(int n,int &min_val, int &cut_num, double &re_len, int &ans)
{
for(int bit=0; bit<(1<<n); bit++) // 二进制枚举
{
int t=0,cut_val=0;
double cut_len=0 ;
for(int i=0; i<n; i++){
if(bit & (1<<i))
{
cut_len+=p[i].l;
cut_val+=p[i].v;
}
else
{
List[t].x=p[i].x;
List[t++].y=p[i].y;
}
}
if(cut_val > min_val) continue; // 一个重要的剪枝
double c=graham(t);
if(cut_len >=c ) // 满足长度限制,也算个剪枝吧
{
if(cut_val < min_val || (cut_val== min_val &&  n-t < cut_num))
{

bd19
min_val=cut_val;
cut_num=n-t;
ans=bit;
re_len=cut_len-c;
}
}
}
}
int main()
{
int n,k=1;
int flag=1;
while(scanf("%d",&n),n)
{
if(!flag) {puts("");}
flag=0;
for(int i=0; i<n; i++)
scanf("%lf%lf%d%d",&p[i].x,&p[i].y, &p[i].v, &p[i].l);
int min_val=inf;
int cut_num=inf;
double re_len=0;
int ans=0;
solve(n,min_val,cut_num,re_len,ans);
printf("Forest %d\n",k++);
printf("Cut these trees:");
for(int i=0 ; i<n; i++){
if(ans & (1<<i))
printf(" %d",i+1);
}
printf("\nExtra wood: %.2lf\n",re_len);
}
return 0;
}


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: