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