简单凸包+暴力枚举。
/*
几何凸包+暴力
*/
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long int64;
//typedef __int64 int64;
typedef pair<int64,int64> PII;
#define MP(a,b) make_pair((a),(b))
const int inf = 0x3f3f3f3f;
const double pi=acos(-1.0);
const int dx[]={1,-1,0,0};
const int dy[]={0,0,1,-1};
const double eps = 1e-8;
const int maxm = 1005;
const int maxn = 16;
struct Point2 {
int x,y;
double val,len;
bool ok;//ok = true 需要去掉的点
}pnt[ maxn ];
int cur[ maxn ];
int cnt_cur;
double val_cur,ans1;
int best[ maxn ];
int cnt_best;
double val_best,ans2;
double Len1,Len2;
struct Point {
double x,y;
bool operator < ( const Point &t ) const {
return y<t.y||( y==t.y&&x<t.x );
}
}a[ maxn ],res[ maxn ];
double xmult( Point sp,Point ep,Point op ){
return (sp.x-op.x)*(ep.y-op.y)-(sp.y-op.y)*(ep.x-op.x);
}
double dist( int i,int j ){
return sqrt( (res[i].x-res[j].x)*(res[i].x-res[j].x)+(res[i].y-res[j].y)*(res[i].y-res[j].y) );
}
int Graham( int n ){
int top = 1;
sort( a,a+n );
if( n==0 ) return 0;
else res[0] = a[0];
if( n==1 ) return 1;
else res[1] = a[1];
if( n==2 ) return 2;
else res[2] = a[2];
for( int i=2;i<n;i++ ){
while( top>0 && xmult(res[top],res[top-1],a[i])>=0 )
top--;
res[ ++top ] = a[i];
}
int len = top;
res[ ++top ] = a[ n-2 ];
for( int i=n-3;i>=0;i-- ){
while( top!=len && xmult( res[top],res[top-1],a[i])>=0 )
top--;
res[ ++top ] = a[i];
}
return top;
}
bool Solve( int n ){
double temp1 = 0;
int cc = 0;
for( int i=0;i<n;i++ ){
if( pnt[i].ok==false ){
a[ cc ].x = 1.0*pnt[ i ].x;
a[ cc ].y = 1.0*pnt[ i ].y;
cc++;
}
else temp1 += pnt[ i ].len;
}
int q = cc;
cc = Graham( q );
double temp2 = 0;
res[ cc ] = res[ 0 ];
for( int i=0;i<cc;i++ ){
temp2 += dist( i,i+1 );
}
ans1 = temp2;
Len1 = temp1;
if( temp2<=temp1 ) return true;
else return false;
}
int main(){
int n;
int Case = 1;
while( scanf("%d",&n),n ){
if( Case!=1 ) printf("\n");
for( int i=0;i<n;i++ ){
scanf("%d%d%lf%lf",&pnt[i].x,&pnt[i].y,&pnt[i].val,&pnt[i].len);
}
int N = (1<<n);
ans1 = ans2 = 0;
val_best = 9999999999.0;
for( int i=0;i<N;i++ ){
cnt_cur = 0;
val_cur = 0;
for( int j=0;j<n;j++ ){
if( i&(1<<j) ){
cur[ cnt_cur++ ] = j;
pnt[ j ].ok = true;
val_cur += pnt[ j ].val;
}
else
pnt[ j ].ok = false;
}
if( cnt_cur==n ) continue;
if( Solve(n)==true ){
//printf("Solve\n");
if( val_cur<val_best ){
val_best = val_cur;
for( int k=0;k<cnt_cur;k++ ){
best[ k ] = cur[ k ];
}
cnt_best = cnt_cur;
ans2 = ans1;
Len2 = Len1;
}
else if( val_cur==val_best ){
if( cnt_cur<cnt_best ){
for( int k=0;k<cnt_cur;k++ ){
best[ k ] = cur[ k ];
}
cnt_best = cnt_cur;
ans2 = ans1;
Len2 = Len1;
}
}
}
}
printf("Forest %d\n",Case++);
printf("Cut these trees: ");
for( int i=0;i<cnt_best;i++ )
printf("%d ",best[i]+1);
printf("\n");
printf("Extra wood: %.2lf\n",Len2-ans2);
}
return 0;
}