题意:n棵树 xi, yi, vi, li
给出每棵树的位置( xi, yi ),价值vi, 砍了这棵树能造多长 的围墙 li
n最大只有15,所以直接采用枚举
满足条件 砍了的树足够将剩下的数围起来(凸包),输出 剩下的树的价值和最大的方案。
存在多种方案时,输出,剩下的树最少的方案
Forest 1 Cut these trees: 砍了哪些树 Extra wood: 砍了的树的li之和 - 剩下的数围成的凸包之长
注意
数据用double类型
只剩两颗树 围墙的长度 = 2 * 两棵树的距离
只剩一颗树 不需要围
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
using namespace std;
struct node
{
double x,y;
double v;
double l;
int num;//编号第几棵树
};
struct repy
{
int status;//二进制上的1表示有这课树
int left;//剩下树的数目
double cost;//花费的价值
double extra;//围完后剩下的木头
};
node tree[20];
repy ret;
int n;
bool cmp(const node &a, const node &b)
{
if(a.y == b.y)
return a.x < b.x;
return a.y < b.y;
}
double mydis(int i, int j)
{
double a = tree[i].x - tree[j].x;
double b = tree[i].y - tree[j].y;
return sqrt(a*a + b*b);
}
double mult(int s,int e, int o)
{
return (tree[s].x-tree[o].x)*(tree[e].y-tree[o].y) - (tree[e].x-tree[o].x)*(tree[s].y-tree[o].y);
}
void check(int s)
{
ret.status = s;
ret.left = 0;
ret.cost = 0;
ret.extra = 0;
int p[20],tn = 0;
int res[20],top = 1;
for(int i = 0; i < n; i++)
{
p[i] = 0;
if(s & (1<<i))
{
ret.left++;
ret.cost += tree[i].v;
p[tn++] = i;
}
else ret.extra += tree[i].l;
}
if(ret.left == 1)
return;
if(ret.left == 2)
{
ret.extra -= 2*mydis(p[0],p[1]);
return;
}
for(int i = 0; i < 3; i++)
res[i] = p[i];
for(int i = 2; i < tn; i++)
{
while(top && mult(p[i],res[top],res[top-1]) >= 0)
top--;
res[++top] = p[i];
}
int len = top;
res[++top] = p[tn-2];
for(int i = tn-3; i >= 0; i--)
{
while(top != len && mult(p[i],res[top],res[top-1]) >= 0)
top--;
res[++top] = p[i];
}
double ans = 0;
for(int i = 0; i < top-1; i++)
{
ans += mydis(res[i],res[i+1]);
}
ans += mydis(res[0],res[top-1]);
ret.extra -= ans;
return ;
}
int main(int argc, char const *argv[])
{
int end,cnt = 0;
int num[20];
repy ans;
while(~scanf("%d", &n) , n)
{
ans.cost = 0;
ans.left = 1e5;
for(int i = 0; i < n; i++)
{
scanf("%lf %lf %lf %lf", &tree[i].x, &tree[i].y, &tree[i].v, &tree[i].l);
tree[i].num = i+1;
}
sort(tree,tree+n,cmp);
end = 1<<n;
for(int s = 1; s < end; s++)
{
check(s);
if(ret.extra > -0.00000001)
{
if(ret.cost > ans.cost)
ans = ret;
else if(ret.cost==ans.cost && ret.left < ans.left)
ans = ret;
}
}
printf("Forest %d\n", ++cnt);
int cou = 0;
for(int i = 0; i < n; i++)
{
if(! (ans.status & (1<<i)))
num[cou++] = tree[i].num;
}
sort(num,num+cou);
printf("Cut these trees:");
for(int i = 0; i < cou; i++)
printf(" %d", num[i]);
printf("\nExtra wood: %.2lf\n\n", ans.extra);
}
return 0;
}