poj1873

此题大意是有n棵树(n < 15),每棵树都有坐标,可形成的木材长度,价值。
求砍掉一些树,这些树的价值尽可能小,使得剩余的树可以用木材围成一个凸包。
并求剩余木材的长度

解法: 枚举所有状态,判断一下能否形成凸包,是否解更优即可。。
注意: 此题有一个剪枝,若当前的枚举状态,砍树价值已经大于得到的最优状态,continue即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 17;
const double EPS = 1e-6;
const int INF = 0x7fffffff;
struct Point
{
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}
    double getDis(Point rhs)
    {
        double xx = rhs.x - x;
        double yy = rhs.y - y;
        return sqrt(xx * xx + yy * yy);
    }
    void input()
    {
        scanf("%lf%lf", &x, &y);
    }

    bool operator <(Point &rhs)
    {
        if(fabs(y - rhs.y) <= EPS) return x < rhs.x;
        return y < rhs.y;
    }
    double x, y;
    double v, l;
    int id;
};
Point operator -(Point lhs, Point rhs){return Point(rhs.x - lhs.x, rhs.y - lhs.y);}
double operator ^(Point lhs, Point rhs){return lhs.x * rhs.y - lhs.y * rhs.x;}

Point point[MAXN];
Point src;
int n;

bool cmp(Point &a, Point &b)
{
    double temp = (a - src) ^ (b - src);
    if(fabs(temp) <= EPS) return a.getDis(src) < b.getDis(src);
    return temp > 0;
}

int stack[MAXN];
void getConvex(vector<Point> &a, vector<Point> &out)
{
    out.clear();
    sort(a.begin(), a.end(), cmp);

    stack[0] = 0;
    stack[1] = 1;
    int top = 1;
    for(int i = 2; i < (int)a.size(); ++i)
    {
        while(top >= 1 && ((a[i] - a[stack[top - 1]]) ^ (a[stack[top]] - a[stack[top - 1]])) >= 0)
        {
            --top;
        }
        stack[++top] = i;
    }
    for(int i = 0; i <= top; ++i) out.push_back(a[stack[i]]);
}

vector<Point> selected;
vector<Point> cut;
vector<Point> ans;
vector<Point> convex;
double extraLength;

void solve()
{
    int MAXBOUND = 1 << n;
    double maxL, curL, curV;
    double bestV = INF;
    bool fst;
    for(int i = 0; i < MAXBOUND; ++i)
    {
        selected.clear();
        cut.clear();
        maxL = curL = curV = 0.0;
        fst = true;
        for(int j = 1; j <= n; ++j)
        {
            int bit = 1 << (j - 1);
            if(bit & i)
            {
                selected.push_back(point[j]);
                if(fst)
                {
                    fst = false;
                    src = point[j];
                }
                else
                {
                    if(point[j] < src) src = point[j];
                }
            }
            else
            {
                cut.push_back(point[j]);
                curV += point[j].v;
                maxL += point[j].l;
            }
        }
        if(selected.size() >= 3)
        {
            if(curV > bestV + EPS) continue;// 剪枝神了!!
            getConvex(selected, convex);
            for(int i = 0; i < (int)convex.size(); ++i)
            {
                // printf("%d ", convex[i].id);
                int nxt = (i + 1) % convex.size();
                curL += convex[i].getDis(convex[nxt]);
            }
            // putchar('\t');
            // if(curL <= maxL)printf("value: %.2lf\n", curV);
            // else putchar('\n');
        }
        else if(selected.size() == 2)
        {
            curL = 2.0 * selected[0].getDis(selected[1]);
        }
        else if(selected.size() == 1)
        {
            curL = 0;
        }

        if(curL <= maxL)
        {
            if(fabs(curV - bestV) <= EPS)
            {
                if(cut.size() < ans.size())
                {
                    ans = cut;
                    extraLength = maxL - curL;
                }
            }
            else if(curV < bestV)
            {
                bestV = curV;
                ans = cut;
                extraLength = maxL - curL;
            }
        }
    }
}

int main()
{
    // freopen("in.txt", "r", stdin);
    int tcase = 0;
    while(scanf("%d", &n) && n != 0)
    {
        if(tcase) putchar('\n');
        ++tcase;

        for(int i = 1; i <= n; ++i)
        {
            scanf("%lf%lf%lf%lf", &point[i].x, &point[i].y, &point[i].v, &point[i].l);
            point[i].id = i;
        }
        solve();
        printf("Forest %d\n", tcase);
        printf("Cut these trees:");
        for(int i = 0; i < (int)ans.size(); ++i)
        {
            printf(" %d", ans[i].id);
        }
        printf("\nExtra wood: %.2lf\n", extraLength);
    }
}