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. IP通信基础学习第二周

    此周的课程学习应该算是我对此科目真正学校生涯的开始吧,尽管我对该科目仍感到很陌生. 课程一开头,老师就给我们简单的介绍了网络的定义.发展及其分类,重点讲了网络拓扑结构及其在局域网上具体的分层情况.该部 ...

  2. java4/9 异常处理

  3. flutter控件之ExpansionPanelList

    import 'package:flutter/material.dart'; class LearnExpansionPanelList extends StatefulWidget{ @overr ...

  4. Python类的私有属性

    class Bar(object): __age = 18 sex = 'male' def __init__(self, ): pass def f(self): print(self.__age) ...

  5. json转数组

    - (NSDictionary *)dataArrayFromJson { NSString *filePath = [[NSBundle mainBundle] pathForResource:@& ...

  6. 剑指offer(27)字符串的排列

    题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述:输入 ...

  7. 剑指offer(45)扑克牌顺子

    题目描述 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决 ...

  8. 剑指offer(63)数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.我们 ...

  9. 继上篇后的Excel批量数据导入

    上篇Excel动态生成模板,此篇将借用此模板进行Excel数据的批量导入. 说明:由于数据库中部分数据储存的是编码或者Id,因此,这里就需要用到上篇中的全局数据,判断是否有数据,有数据直接使用,没有数 ...

  10. 复旦大学2016--2017学年第一学期(16级)高等代数I期末考试第七大题解答

    七.(本题10分)  设 $A,B$ 均为 $m\times n$ 阶实矩阵, 满足 $A'B+B'A=0$. 证明: $$r(A+B)\geq\max\{r(A),r(B)\},$$并且等号成立的充 ...