POJ_1873

    由于树木比较少,可以枚举砍树的决策,然后计算砍掉的树木的长度是否比剩下的树木的凸包的周长要长,每次计算之后按题意更新最优解即可。

    在枚举的时候还可以应用一个剪枝,就是如果当前砍树损失的价值比记录的最小价值要大的话,就可以直接枚举下一种情况了,而不必再去花时间计算凸包和凸包的周长了,这样可以节省很多时间。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define MAXD 20
#define zero 1e-8
#define INF 0x3f3f3f3f
struct point
{
int x, y;
}p[MAXD], res[MAXD], q[MAXD];
int st, N, X, P, num, minv, v[MAXD];
double w[MAXD], ans;
int cmp(const void *_p, const void *_q)
{
point *p = (point *)_p, *q = (point *)_q;
if(p->y == q->y)
return p->x - q->x;
return p->y - q->y;
}
int dcmp(double x)
{
return fabs(x) < 0 ? 0 : (x < 0 ? -1 : 1);
}
double sqr(double x)
{
return x * x;
}
int det(int x1, int y1, int x2, int y2)
{
return x1 * y2 - x2 * y1;
}
void init()
{
int i, j, k;
for(i = 0; i < N; i ++)
scanf("%d%d%d%lf", &p[i].x, &p[i].y, &v[i], &w[i]);
}
int del(int top, int i)
{
if(det(res[top].x - res[top - 1].x, res[top].y - res[top - 1].y, q[i].x - res[top].x, q[i].y - res[top].y) <= 0)
return 1;
return 0;
}
int graham()
{
int i, j, k, top = 1, mint;
qsort(q, X, sizeof(q[0]), cmp);
res[0] = q[0], res[1] = q[1];
for(i = 2; i < X; i ++)
{
while(top && del(top, i))
-- top;
res[++ top] = q[i];
}
mint = top;
res[++ top] = q[X - 2];
for(i = X - 3; i >= 0; i --)
{
while(top != mint && del(top, i))
-- top;
res[++ top] = q[i];
}
return top;
}
double calculate()
{
int i, j, k;
double t;
if(X == 1)
t = 0;
else if(X == 2)
t = 2 * sqrt(sqr(q[0].x - q[1].x) + sqr(q[0].y - q[1].y));
else
{
P = graham();
t = 0;
for(i = 0; i < P; i ++)
t += sqrt(sqr(res[i].x - res[i + 1].x) + sqr(res[i].y - res[i + 1].y));
}
return t;
}
void solve()
{
int i, j, k, cnt, value;
double t, s;
minv = num = INF;
for(k = 1; k < (1 << N); k ++)
{
s = cnt = value = X = 0;
for(j = 0; j < N; j ++)
{
if((1 << j) & k)
{
++ cnt;
value += v[j];
s += w[j];
}
else
q[X ++] = p[j];
}
if(value > minv)
continue;
t = calculate();
if(dcmp(s - t) < 0)
continue;
if(value < minv || (value == minv && cnt < num))
{
minv = value;
num = cnt;
st = k;
ans = s - t;
}
}
printf("Cut these trees:");
for(i = 0; i < N; i ++)
if((1 << i) & st)
printf(" %d", i + 1);
printf("\n");
printf("Extra wood: %.2lf\n", ans);
}
int main()
{
int t = 0;
for(;;)
{
scanf("%d", &N);
if(!N)
break;
init();
if(t ++)
printf("\n");
printf("Forest %d\n", t);
solve();
}
return 0;
}


posted on 2012-02-18 22:03  Staginner  阅读(265)  评论(0编辑  收藏  举报