题目描述:

The Fortified Forest

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 7818   Accepted: 2149

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.

样例输入:

60  0  8  31  4  3  22  1  7  14  1  2  33  5  4  62  3  9  8
33  0 10  25  5 20 257 -3 30 32
0

样例输出:

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

解题思路:

因为n<=15,所以范围不大。两种方法:1.搜索+凸包 2.状态压缩+凸包  事实上,因为加上各种剪枝后时间效率会大大增加,所以搜索可能反而会更快一些。但是由于我一向不喜欢暴力,所以我强迫自己用第二种方法做。

简单介绍一下第二种方法:

1.每棵树的状态可用1或0表示,1表示砍掉这棵树,0表示不砍。那么这个树林的情况就可以用二进制数来表达。比如:100101,表示第一棵、第三棵、第六棵会被砍掉(倒过来看)。同时可以将二进制数转化为十进制数。比如:100101(还是那个数)就是十进制中的37。所以我们任意一个十进制数,都可以用转为二进制数,从而表达一片树林的状态。这样一来,我们直接可以for循环,从0到2的n次方减1(最多有n棵树被砍掉)

2.每一个新的状况对应着新的凸包,所以要及时更新变量和数组。

3.凸包要特判一下只剩下0棵树和1棵树的情况,不然会卡住

4.这道题很容易wa的原因在于——长度要用double类型,千万别用int!

5.由于有多组数据,注意要及时更新。总而言之,水题一道。

附上c++代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{double x,y,v,l;
}a[2100],p[2100],sta[2100];
double multi(node n1,node n2,node no){return (n1.x-no.x)*(n2.y-no.y)-(n2.x-no.x)*(n1.y-no.y);}
double dis(node n1,node n2){return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));}
int n,dd=0,top=0,nn=0,k=99999999,kk=0;
double ans=0,aans=0;
double sum=0,len=0,s=0;
int maxx;
bool bo[20];
int aa[20];
bool cmp(node n1,node n2)
{double t=multi(n1,n2,p[1]);if(t==0 && dis(n1,p[1])<dis(n2,p[1]))return true;return t>0;
}
void graghm()
{top=0;sort(p+2,p+nn+1,cmp);for(int i=1;i<=2;i++)sta[++top]=p[i];for(int i=3;i<=nn;i++){while(top>2 && multi(sta[top],p[i],sta[top-1])<=0)top--;sta[++top]=p[i];}
}
void make(int d)
{memset(bo,true,sizeof(bo));aans=0,s=0;len=0;kk=n;int i=1;while(d!=0){if(d%2==1)bo[i]=false,s+=a[i].l,kk--;d/=2;i++;}for(int i=1;i<=n;i++)if(bo[i]==true)aans+=a[i].v;nn=0;for(int i=1;i<=n;i++){if(bo[i]==true){p[++nn]=a[i];if(p[nn].y<p[1].y || (p[nn].y==p[1].y && p[nn].x<p[1].x))swap(p[1],p[nn]);}}if(kk==1)len=0;if(kk>1){graghm();for(int i=2;i<=top;i++)len+=dis(sta[i],sta[i-1]);len+=dis(sta[1],sta[top]);}
}
int main()
{int t=0;while(scanf("%d",&n)!=EOF){if(n==0)break;t++;ans=0;k=999999999;dd=0;for(int i=1;i<=n;i++){scanf("%lf%lf%lf%lf",&a[i].x,&a[i].y,&a[i].v,&a[i].l);}maxx=(1<<n)-1;for(int i=0;i<maxx;i++){make(i);if((ans<aans && s-len>=0) || (ans==aans && kk<k)){ans=aans;sum=s-len;dd=0;k=kk;for(int j=1;j<=n;j++)if(!bo[j])aa[++dd]=j;}}printf("Forest %d\n",t);printf("Cut these trees: ");for(int i=1;i<=dd;i++)printf("%d ",aa[i]);printf("\nExtra wood: %.2f\n\n",sum);}return 0;
}

如果还有疑问,欢迎向我的邮箱提问——gongxiaohanxh@126.com,我都乐意回答的哦~

【poj】1873: The Fortified Forest (凸包+状态压缩+各种搞事)相关推荐

  1. POJ 1873 The Fortified Forest 凸包 二进制枚举

    n最大15,二进制枚举不会超时.枚举不被砍掉的树,然后求凸包 #include<stdio.h> #include<math.h> #include<algorithm& ...

  2. POJ 1873 The Fortified Forest(枚举+凸包+剪枝)

    POJ 1873 The Fortified Forest 题意: 某王有一些树,要制作一个栅栏将所有树围起来,栅栏制作木材来源就是砍去其中一些树. 现在输入每棵树的坐标,价值,高度,求出所围价值最大 ...

  3. POJ 1873 The Fortified Forest (凸包,状态压缩枚举)

    题目链接:http://poj.org/problem?id=1873 题意:给出一些树,每棵树有坐标,高度,以及价值,要求砍掉一些树,用那些木材,将其它树围起来,要求花最小的代价,代价相同,要求砍掉 ...

  4. poj 1873 The Fortified Forest (位运算枚举 + 凸包周长)

    题目链接:http://poj.org/problem?id=1873 大意:有一片N棵树的森林,要从中砍掉几棵树做成篱笆,把剩下的树围起来 输入:给N课树,每棵树的坐标是x,y,每棵树有一个vi和l ...

  5. POJ 1873 The Fortified Forest(凸包)

    http://poj.org/problem?id=1873 题目大意: 给你n棵树每棵树的坐标,高度,价值,要求砍掉一些树,用那些木材,将其它树围起来,要求花最小的代价,代价相同,要求砍掉最少的树. ...

  6. POJ 1873 The Fortified Forest(凸包)题解

    题意:二维平面有一堆点,每个点有价值v和删掉这个点能得到的长度l,问你删掉最少的价值能把剩余点围起来,价值一样求删掉的点最少 思路:n<=15,那么直接遍历2^15,判断每种情况.这里要优化一下 ...

  7. ●POJ 1873 The Fortified Forest

    题链: http://poj.org/problem?id=1873 题解: 计算几何,凸包 枚举被砍的树的集合.求出剩下点的凸包.然后判断即可. 代码: #include<cmath> ...

  8. Uva5211/POJ1873 The Fortified Forest 凸包

    LINK 题意:给出点集,每个点有个价值v和长度l,问把其中几个点取掉,用这几个点的长度能把剩下的点围住,要求剩下的点价值和最大,拿掉的点最少且剩余长度最长. 思路:1999WF中的水题.考虑到其点的 ...

  9. POJ 2411 Mondriaan's Dream [经典状态压缩dp]

    题意:略. 思路:这一题开始做的时候完全没有思路,便去看了别人的题解. 首先,对于这个题目解法想有一个初步的了解,请看这里:http://www.2cto.com/kf/201208/146894.h ...

最新文章

  1. ggplot2 调整绘图区域大小
  2. 【vim】几种模式的切换
  3. python 无头浏览器xhr 文件_Python对Selenium调用浏览器进行封装包括启用无头浏览器,及对应的浏览器配置文件...
  4. petshop4.0 详解之二(数据访问层之数据库访问设计)
  5. 《目标检测》YOLO、SSD简单学习
  6. 95-910-148-源码-FlinkSQL-Flink SQL自定义聚合函数
  7. 第二周作业 wordcount
  8. linux如何打开dhcp服务,怎么开启DHCP服务器啊
  9. 游戏开发之C++指针的妙用(C++)
  10. Ubuntu安装显卡驱动详细步骤
  11. Java编程降序排序代码,Java选择排序(升序跟降序)
  12. PostGIS 爆管分析之找出上游阀门
  13. PV,UV,IP,VV,CV的含义与区别
  14. 基带丢失、IMEI丢失、手机无信号--高通通用解决办法
  15. 各种音视频编解码学习详解之 编解码学习笔记(四):Mpeg系列——Mpeg 4
  16. 内容制作新纪元:AIGC技术的革命性影响
  17. Django 4.0文档学习(一)
  18. 梦在远方,你依然在心上
  19. Linux X11远程图形桌面显示
  20. pta c语言 选择法排序

热门文章

  1. 小程序如何防御DDOS攻击?
  2. 【敏捷6.2】授权型的高绩效团队
  3. was控制台java虚拟机默认值_JVM 参数设置
  4. PHP日志库 - Monolog 知识整理
  5. 算法学习与填充计划---2023.2.21---夏目
  6. html5中怎么制作一个盒子,亲手制作一个折纸盒子超有成就感 这个教程超级简单的...
  7. 由百度关键词联想联想到的
  8. validationEngine
  9. 小程序获取手机号码解密偶尔会失败
  10. 针对转动的自适应轮毂装饰盖