基本思想是:用dfs求最佳解;判断解是否成立是,要用砍倒的长度和凸包周长进行对比,这里求凸包

  http://acm.pku.edu.cn/JudgeOnline/problem?id=1873

#include <cmath>
#include
<cstdio>
#include
<memory>
#include
<algorithm>
#include
<iostream>
#include
<stdlib.h>
#include
<string.h>
using namespace std;
#define Infinity 1e+10 //最大值的设定
typedef
double TYPE;

//空间中的点,可以用来作为二维点来用
struct POINT {/*验证*/
TYPE x; TYPE y; TYPE z;
TYPE v, l;
//本题额外增加的 价值,能做成围栏的长度
int order;//该树的序号
POINT() : x(0), y(0), z(0) {};
POINT(TYPE _x_, TYPE _y_, TYPE _z_
= 0)
: x(_x_), y(_y_), z(_z_) {};
//要用 G++ 提交 ,可以不用这个
POINT operator =(const POINT &A){
x
= A.x; y = A.y; z = A.z;
v
= A.v; l = A.l;
order
= A.order;
}
};

POINT p[
20];
POINT p_fb[
20];
POINT fence[
20];
TYPE extra;
POINT real_fence[
20];
TYPE Value;
int real_fence_tree;
bool mark[20];//判断这个点要不要用到

// 多边形 ,逆时针或顺时针给出x,y
struct POLY {/*验证*/
//n个点
int n;
//x,y为点的指针,首尾必须重合
TYPE * x;
TYPE
* y;
POLY() : n(
0), x(NULL), y(NULL) {};
POLY(
int _n_, const TYPE * _x_, const TYPE * _y_) {
n
= _n_;
x
= new TYPE[n + 1];
memcpy(x, _x_, n
*sizeof(TYPE));
x[n]
= _x_[0];
y
= new TYPE[n + 1];
memcpy(y, _y_, n
*sizeof(TYPE));
y[n]
= _y_[0];
}
};
// cross product of (o->a) and (o->b)
// 判断o->a 在 o->b 的哪边,如果在 o->b 的左边则为负数,在右边则为正数
// 叉乘
TYPE Cross(const POINT & a, const POINT & b, const POINT & o) {/*验证*/
return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}

// planar points' distance
// 两个点的距离
TYPE Distance(const POINT & a, const POINT & b) { /*验证*/
return
sqrt((a.x
- b.x) * (a.x - b.x) + (a.y - b.y)
* (a.y - b.y) + (a.z - b.z) * (a.z - b.z));
}
//多边形顶点
POINT Vertex(const POLY & poly, int idx) {//idx 表示第几个点 /*验证*/

idx
%= poly.n;
return POINT(poly.x[idx], poly.y[idx]);
}
//多边形的周长
TYPE Perimeter(const POLY & poly) { /*验证*/
TYPE p
= 0.0;
for (int i = 0;i < poly.n; i++)
p
= p + Distance(Vertex(poly, i),
Vertex(poly, i
+ 1));
return p;
}
// 点阵的凸包,返回一个多边形
POLY ConvexHull(const POINT * set, int n) // 不适用于点少于三个的情况

{
/*验证*/
POINT
* points = new POINT[n];
memcpy(points,
set, n * sizeof(POINT));
TYPE
* X = new TYPE[n];
TYPE
* Y = new TYPE[n];
long i, j, k = 0, top = 2;
for(i = 1; i < n; i++) {
if ((points[i].y < points[k].y)
|| ((points[i].y == points[k].y)
&& (points[i].x < points[k].x)))
{
k
= i;
}
}
std::swap(points[
0], points[k]);
for (i = 1; i < n - 1; i++) {
k
= i;
for (j = i + 1; j < n; j++) {
if ((Cross(points[j], points[k], points[0]) > 0)
||((Cross(points[j], points[k], points[0]) == 0)
&&(Distance(points[0], points[j]) < Distance(points[0], points[k]))))
{
k
= j;
}
}
std::swap(points[i], points[k]);
}
X[
0] = points[0].x;
Y[
0] = points[0].y;
X[
1] = points[1].x;
Y[
1] = points[1].y;
X[
2] = points[2].x;
Y[
2] = points[2].y;
for (i = 3; i < n; i++) {
while (Cross(points[i], POINT(X[top], Y[top]), POINT(X[top - 1], Y[top - 1])) >= 0 && top>0)
{
top
--;
}
++top;
X[top]
= points[i].x;
Y[top]
= points[i].y;
}
delete [] points;
POLY poly(
++top, X, Y);
delete [] X;
delete [] Y;
return poly;
}

void dfs(int fence_tree, int size_p_fb,int n){
TYPE fence_len
=0;
TYPE value
=0;
for(int i=0;i<fence_tree;i++){
fence_len
+=fence[i].l;
value
+= fence[i].v;
}
if(value > Value) return;

TYPE need_len
=0;
if(size_p_fb>=3){
POLY poly
=ConvexHull(p_fb, size_p_fb);
need_len
= Perimeter(poly);
}
else if(size_p_fb==2){
need_len
=2.0*(Distance(p_fb[0],p_fb[1]));
}
if(fence_len>=need_len){
if(value < Value){
Value
=value;
for(int i=0;i<fence_tree;i++){
real_fence[i]
=fence[i];
}
extra
=fence_len-need_len;
real_fence_tree
=fence_tree;
}
else if(value == Value){
if(fence_tree <real_fence_tree ){
for(int i=0;i<fence_tree;i++){
real_fence[i]
=fence[i];
}
extra
=fence_len-need_len;
real_fence_tree
=fence_tree;
}

}
}
for(int i=0; i< n; i++){
if(mark[i]==false){
mark[i]
=true;
size_p_fb
=0;
fence[fence_tree]
=p[i];
for(int j=0; j< n;j++){
if(mark[j]==false){
p_fb[size_p_fb]
=p[j];
size_p_fb
++;
}
}
dfs(fence_tree
+1,size_p_fb,n);
mark[i]
=false;
}
}
}
void init(int n){
memset(mark,
false,sizeof(mark));
extra
=0;
for(int j=0; j< n;j++){
p_fb[j]
=p[j];
}
real_fence_tree
=0;
Value
= Infinity;
}
int main(){
int n;
int cases =1;

while(cin>>n,n!=0){
if(cases != 1)
printf(
"\n");
for(int i=0;i<n; i++){
scanf(
"%lf%lf%lf%lf",&p[i].x,&p[i].y,&p[i].v,&p[i].l);
p[i].order
=i+1;
}
init(n);
dfs(
0,n,n);
printf(
"Forest %d\n",cases);
printf(
"Cut these trees:");
for(int i=0;i< real_fence_tree;i++){
printf(
" %d",real_fence[i].order);
}

printf(
"\n");
printf(
"Extra wood: %.2f\n",extra);


cases
++;
}
return 0;
}

posted on 2011-05-09 13:11  敌敌  阅读(337)  评论(0编辑  收藏  举报