poj 1873 World Final的水题,先求凸包,然后再搜索。由于规模不大,可以使用位运算枚举...

基本思想是:用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 ;
}

转载于:https://www.cnblogs.com/laipDIDI/articles/2041062.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值