The Fortified Forest
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 7291   Accepted: 2031

Description

Once upon a time, in a faraway land, there lived a king. This king owned a small collection of rare and valuable trees, which had been gathered by his ancestors on their travels. To protect his trees from thieves, the king ordered that a high fence be built around them. His wizard was put in charge of the operation. 
Alas, the wizard quickly noticed that the only suitable material available to build the fence was the wood from the trees themselves. In other words, it was necessary to cut down some trees in order to build a fence around the remaining trees. Of course, to prevent his head from being chopped off, the wizard wanted to minimize the value of the trees that had to be cut. The wizard went to his tower and stayed there until he had found the best possible solution to the problem. The fence was then built and everyone lived happily ever after.

You are to write a program that solves the problem the wizard faced.

Input

The input contains several test cases, each of which describes a hypothetical forest. Each test case begins with a line containing a single integer n, 2 <= n <= 15, the number of trees in the forest. The trees are identified by consecutive integers 1 to n. Each of the subsequent n lines contains 4 integers xi, yi, vi, li that describe a single tree. (xi, yi) is the position of the tree in the plane, vi is its value, and li is the length of fence that can be built using the wood of the tree. vi and li are between 0 and 10,000. 
The input ends with an empty test case (n = 0). 

Output

For each test case, compute a subset of the trees such that, using the wood from that subset, the remaining trees can be enclosed in a single fence. Find the subset with minimum value. If more than one such minimum-value subset exists, choose one with the smallest number of trees. For simplicity, regard the trees as having zero diameter. 
Display, as shown below, the test case numbers (1, 2, ...), the identity of each tree to be cut, and the length of the excess fencing (accurate to two fractional digits).

Display a blank line between test cases.

Sample Input

6
0 0 8 3
1 4 3 2
2 1 7 1
4 1 2 3
3 5 4 6
2 3 9 8
3
3 0 10 2
5 5 20 25
7 -3 30 32
0

Sample Output

Forest 1
Cut these trees: 2 4 5
Extra wood: 3.16 Forest 2
Cut these trees: 2
Extra wood: 15.00

Source

题意:平面上有n棵树,给出他们的坐标x,y,价值 v,可以做成篱笆的长度,要求你求出砍掉最小价值的树并且使得砍掉的树做成的篱笆可以把剩下的树围起来 。
当价值相同时,要求砍掉的树最少。
思路:因为这道题的n的范围很小,所以可以用二进制枚举所有的情况,找出最优解。
代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#define zero(a) (fabs((double)(a))<(1e-8))
using namespace std;
const int eps=1e-8;
struct tr{
int x,y,v,l;
}s1[20],s[20];
int st[20];
int mul(tr p,tr u,tr v){//求叉积
return (p.x-u.x)*(v.y-u.y)-(v.x-u.x)*(p.y-u.y);
}
double dis(tr a,tr b){//求长度
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(tr a,tr b){//极角排序
if(mul(a,s[0],b)>0)//以最小点s[0]为基准排序
return true;
else if(zero(mul(a,s[0],b))&&dis(s[0],a)<dis(s[0],b))
return true;
return false;
}
int mv,ct,nt;
double l2;
int do1(int n,int l1,int mv1,int c){
int i,j;
int x,y;
double l;//要用的木材长度
if(n==1){
l=0;
}
/*else if(n==2){
l=dis(s[0],s[1])*2;
}*/
else{
l=0;
for(i=1;i<n;i++){
if(s[0].y>s[i].y||(s[0].y==s[i].y&&s[0].x>s[i].x)){//将s[0]化为最小点,以便极角排序
swap(s[0],s[i]);
}
}
sort(s+1,s+n,cmp);//排序
int top,cnt;
st[0]=0;
st[1]=1;
tr a,b;
top=2;
cnt=2;
while(cnt<n-1){//当
st[top]=cnt;//先放入当前点
top++;
cnt++;
a=s[st[top-1]];
b=s[st[top-2]];
while(mul(s[cnt],a,b)<eps){//以当前点的下一个点为标杆点来除去不合凸包条件的点(Graham扫描法)(如果标杆点在当前栈顶的两个点组成的直线的右边,则说明栈顶的点不是凸包上的点)
top--;//去掉不合条件的点
a=b;//重新判断当前栈顶的点
b=s[st[top-2]];
}
}
st[top++]=n-1;//压入最后一次的标杆点,它一定是凸包上的点,因为它在最左边
for( i=0;i<top-1;i++){
l+=dis(s[st[i]],s[st[i+1]]);
}
l+=dis(s[0],s[n-1]);//把这句代码写成了l+=dis(s[st[0]],s[st[n-1]]),卡了三个小时,QAQ,引以为戒啊
}
//printf("%d %d\n",l1,l);
if((l1-l)>=0){// 砍掉的树可以把剩下的树围起来
if(mv1>mv){//剩下树的价值要最大
l2=l1-l;
nt=n;
mv=mv1;
ct=c;
}
else if(mv1==mv&&nt<=n){//价值相同时砍掉的树要最少
l2=l1-l;
nt=n;
mv=mv1;
ct=c;
}
}
return 0;
}
int main(){
int n,i,j,k=0;
int a,b,cnt,c;
int mv1;
while(scanf("%d",&n)!=EOF&&n){
k++;
nt=0;
for(i=0;i<n;i++){
scanf("%d%d%d%d",&s1[i].x,&s1[i].y,&s1[i].v,&s1[i].l);
}
mv=0;
ct=0;
for(j=1;j<(1<<n)-1;j++){//二进制枚举
//printf("%d\n",j);
a=j,b=0;
cnt=0;
mv1=0;
int l1=0;
for(i=0;i<n;i++){
if(((1<<i)&j)){//按位与
s[cnt++]=s1[i];//放入不砍的树
mv1+=s1[i].v;//剩余的价值
}
else{
l1+=s1[i].l;//可以做篱笆的长度
}
}
if(mv>mv1)//剩下的价值小于最优的价值
continue;
do1(cnt,l1,mv1,j);
}
printf("Forest %d\n",k);
printf("Cut these trees:");
for(i=0;i<n;i++)
if(!((1<<i)&ct)) printf(" %d",i+1);
printf("\n");
printf("Extra wood: %.2f\n\n",l2);
}
return 0;
}

  

poj1873(枚举+凸包)的更多相关文章

  1. POJ 1873 The Fortified Forest(枚举+凸包)

    Description Once upon a time, in a faraway land, there lived a king. This king owned a small collect ...

  2. POJ 3135 Polygons on the Grid(枚举+凸包)

    题目大意是让你用这n条边放在网格上构成凸包,并且边的两端点必须在网格上. 那么比较容易想到的就是枚举可能情况,因为这样的勾股数组成情况不多,因此可以直接枚举所有连出去的边反映在坐标轴上的所有情况,最后 ...

  3. POJ 1873 - The Fortified Forest 凸包 + 搜索 模板

    通过这道题发现了原来写凸包的一些不注意之处和一些错误..有些错误很要命.. 这题 N = 15 1 << 15 = 32768 直接枚举完全可行 卡在异常情况判断上很久,只有 顶点数 &g ...

  4. HDU 3685 Rotational Painting(多边形质心+凸包)(2010 Asia Hangzhou Regional Contest)

    Problem Description Josh Lyman is a gifted painter. One of his great works is a glass painting. He c ...

  5. poj 2187 凸包加旋转卡壳算法

    题目链接:http://poj.org/problem?id=2187 旋转卡壳算法:http://www.cppblog.com/staryjy/archive/2009/11/19/101412. ...

  6. (hdu step 7.1.5)Maple trees(凸包的最小半径寻找掩护轮)

    称号: Maple trees Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...

  7. BZOJ2300[HAOI2011]防线修建——非旋转treap+凸包(平衡树动态维护凸包)

    题目描述 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于 ...

  8. POJ 2187 - Beauty Contest - [凸包+旋转卡壳法][凸包的直径]

    题目链接:http://poj.org/problem?id=2187 Time Limit: 3000MS Memory Limit: 65536K Description Bessie, Farm ...

  9. [hdu3685]Rotational Painting 凸包 重心

    大致题意: 给出一个多边形,问你有多少种放法可以使得多边形稳定得立在平面上. 先对多边形求重心,在求凸包,枚举凸包的边,如果重心没有在边的范围内,则不行 判断是否在范围内可用点积来判断 #includ ...

随机推荐

  1. Java代码走查具体考察点

    代码走查具体考察点 一.参数检验 公共方法都要做参数的校验,参数校验不通过,需要明确抛出异常或对应响应码. 在接口中也明确使用验证注解修饰参数和返回值,作为一种协议要求调用方按注解约束传参,返回值验证 ...

  2. Django之天天生鲜项目

    准备工作 1.配置settings.py内置文件 注意: AUTH_USER_MODEL配置参数要在第一次迁移数据库之前配置,否则可能django的认证系统工作不正常 2.创建应用 3.配置主路由 一 ...

  3. 虚拟机linux下安装tomcat外部可访问

    1.解压tomcat压缩包 tar -zxvf apache-tomcat 2.启动tomcat 进入bin目录下 ./catalina.sh run  (startup.sh不会显示日志信息) 3. ...

  4. double保留两位小数

    public static String format(double dValue, int lScale) { // ////负数,则装化为正数后进行四舍五入 boolean bFlag = fal ...

  5. CSS 内边距 外边距

    CSS 内边距 外边距 <html> <!-- style="margin: 0 auto" 将网页上方空白边距填满--> <body style=& ...

  6. Mysql 数据类型、约束类型

    mysql数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型.   数值类型 MySQL支持所有标准 ...

  7. Python爬虫——你们要的王者荣耀高清图

    曾经144区的王者 学了计算机后 头发逐渐从李白变成了达摩 秀发有何用,变秃亦变强 (emmm徒弟说李白比达摩强,变秃不一定变强) 前言 前几天开了农药的安装包,发现农药是.Net实现的游戏 虽然游戏 ...

  8. vue_elementUI_ tree树形控件 获取选中的父节点ID

    el-tree 的 this.$refs.tree.getCheckedKeys() 只可以获取选中的id 无法获取选中的父节点ID想要获取选中父节点的id;需要如下操作1. 找到工程下的node_m ...

  9. Codeforces 955F Heaps - 动态规划

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一棵以1为根的树,定义$dp_{k}(u)$表示在$u$的子树内存在的深度最大的满k叉树的深度,求$\sum_{u = 1}^{n}\su ...

  10. 关于变量,JAVA基本数据类型,运算符类型,如何从控制台接收输入的数据

    一,变量与变量的使用 1.变量是在程序运行中其值可以改变的量,java程序的一个基本存储单元 2.变量的使用 变量类型+变量名 二,JAVA基本数据类型 1.数值型a.整点类型(byte.short. ...