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. ACM-ICPC 2018 南京赛区网络预赛 Solution

    A. An Olympian Math Problem cout << n - 1 << endl; #include <bits/stdc++.h> using ...

  2. https://scrapingclub.com/exercise/basic_captcha/

    def parse(self, response): # set_cookies = response.headers.getlist("set-cookie").decode(& ...

  3. shell 三剑客

    grep 过滤来自一个文件或标准输入匹配模式内容. 除了grep外,还有egrep.fgrep.egrep是grep的扩展,相当于grep -E.fgrep相当于grep -f,用的少. Usage: ...

  4. Linux服务器---百科mediawiki

    Mediawiki         Mediawiki是一个强大的维基软件,可以实现页面编辑.图像和多媒体管理. 1.下载mediawiki软件(“https://www.mediawiki.org/ ...

  5. EPOCH batchsize

    只有在数据很庞大的时候(在机器学习中,几乎任何时候都是),我们才需要使用 epochs,batch size,迭代这些术语,在这种情况下,一次性将数据输入计算机是不可能的.因此,为了解决这个问题,我们 ...

  6. jQuery 查找属性

    jQuery 查找属性 示例: <div xsk='123' > <div xsk='456' > // 具有xsk属性的所有标签 $('[xsk]') // xsk属性等于1 ...

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

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

  8. iOS开发 -------- AFNetworking实现简单的断点下载

    一 实现如下效果   二 实现代码 // // ViewController.m // AFNetworking实现断点下载 // // Created by lovestarfish on 15/1 ...

  9. linux(centos)测试带宽

    1.安装speedtest-cli speedtest-cli是一个用Python编写的轻量级Linux命令行工具,在Python2.4至3.4版本下均可运行.它基于Speedtest.net的基础架 ...

  10. Learning-Python【15】:内置函数

    截止到Python版本3.6.2,一共为我们提供了68个内置函数.它们就是Python提供的直接可以拿来使用的所有函数. 这个表的顺序是按照首字母的排列顺序来的,都混乱的堆在一起.比如,oct和bin ...