题目链接:http://poj.org/problem?id=1873
Description
Input
Output
Sample Input
6 0 0 8 3 1 4 3 2 2 1 7 1 4 1 2 3 3 5 4 6 2 3 9 8 3 3 0 10 2 5 5 20 25 7 -3 30 32 0
Sample Output
Forest 1 Cut these trees: 2 4 5 Extra wood: 3.16 Forest 2 Cut these trees: 2 Extra wood: 15.00
Source
有n棵树(n<=15), 每棵树的价值为 v , 砍掉这个树能得到长度为 l 的木板。
现在要砍掉其中的一些树,用来造木板把剩余的所有树围起来,(每颗树只有砍与不砍两种状态),
问要造这种木板最少需要消耗多少的价值(砍掉的树的 v 的和),
输出需要砍掉哪些树和剩余的木板长度(砍掉的树形成的木板并且包围未砍掉的树没有用完的木板长度)。
PS:
n比较小,我们可以枚举砍掉的树!
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
const double eps = 1e-8;
const double PI = acos(-1.0);
const int MAXN = 1010;
int sgn(double x)
{
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
struct Point
{
int x, y;
int v, l;
Point() {}
Point(int _x, int _y)
{
x = _x;
y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x,y - b.y);
}
//叉积
double operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
//点积
double operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
};
Point list[MAXN], tr[MAXN];
int Stack[MAXN], top;
//*两点间距离
double dist(Point a,Point b)
{
return sqrt((a-b)*(a-b));
}
//相对于list[0]的极角排序
bool _cmp(Point p1,Point p2)
{
double tmp = (p1-list[0])^(p2-list[0]);
if(sgn(tmp) > 0)return true;
else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
return true;
else return false;
}
void Graham(int n)
{
Point p0;
int k = 0;
p0 = list[0];
//找最下边的一个点
for(int i = 1; i < n; i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if(n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for(int i = 2; i < n; i++)
{
while(top > 1 &&
sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <=
0)
top--;
Stack[top++] = i;
}
}
int main()
{
int n;
int cas = 0;
int ans[20];
while(scanf("%d",&n) && n)
{
int x, y, v, l;
int pnum;//最少砍掉的数量
double rest = 0;//剩余的长度
int min_tree = n+1;
int min_val = INF;
for(int i = 0; i < n; i++)
{
scanf("%d%d%d%d",&tr[i].x,&tr[i].y,&tr[i].v,&tr[i].l);
}
for(int i = 0; i < (1<<n); i++)
{
double len, val;
int num;
len = num = val = 0;
int k = 0;
int vis[27];
memset(list,0,sizeof(list));
for(int j = 0; j < n; j++)
{
vis[j] = 0;
if(i & (1<<j))//砍掉
{
val+=tr[j].v;
len+=tr[j].l;
num++;
vis[j] = 1;
}
else
{
list[k++] = Point(tr[j].x, tr[j].y);
}
}
if(val > min_val || (val==min_val && min_tree < num))
{
continue;
}
if(len == 0 && k != 1)
{
continue;
}
Graham(k);
double res = 0;//凸包周长
for(int h = 0; h < top-1; h++)
{
res+=dist(list[Stack[h]],list[Stack[h+1]]);
}
res+=dist(list[Stack[0]],list[Stack[top-1]]);
//printf("len::%.2lf >>res:%.2lf, ans::%.2lf\n",len,res,len-res);
if(res <= len)//能包围
{
min_val = val;
min_tree = num;
rest = len - res;
pnum = 0;
for(int f = 0; f < n; f++)
{
if(vis[f])
{
ans[pnum++] = f;
}
}
}
}
printf("Forest %d\n",++cas);
printf("Cut these trees:");
for(int i = 0; i < pnum; i++)
{
printf(" %d",ans[i]+1);
}
printf("\nExtra wood: %.2f\n\n", rest);
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 1873 The Fortified Forest(凸包+枚举 World Finals 1999啊)
原文地址:http://blog.csdn.net/u012860063/article/details/47302875