POJ 1873 The Fortified Forest 二进制枚举 + 凸包 (final水题)

RT,注意考虑凸包点数小于3的情况

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;

#define eps 1e-8
#define inf 1<<29

struct point
{
    int x, y;
    point(){}
    point(int xx, int yy) : x(xx), y(yy){}
};

struct data
{
    int x, y, v, l;
}d[16];

int det(int x1, int y1, int x2, int y2)
{
    return x1 * y2 - x2 * y1;
}

int cross(point o, point a, point b)
{
    return det(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y);
}

double f(int x)
{
    return x * x * 1.0;
}

double dis(point a, point b)
{
    return sqrt( f(a.x - b.x) + f(a.y - b.y) );
}

int min_v, min_n;
int n, m;
bool vis[17];
int con[17];

bool cmp(point a, point b) //水平序
{
    if(a.y == b.y) return a.x < b.x;
    return a.y < b.y;
}

double graham(point p[], int n, int len) //返回剩余的长度
{
    if(n == 0 || n == 1) return len * 1.000;
    if(n == 2) return len * 1.000 - 2 * dis(p[0], p[1]);
    int i;
    sort(p, p + n, cmp);
    int top = 0;
    point res[17];
    for(i = 0; i < n; i++)
    {
        while(top >= 2 && cross(res[top-2], res[top-1], p[i]) < 0)
            top--;
        res[top++] = p[i];
    }
    int t = top + 1;
    for(i = n - 2; i >= 0; i--)
    {
        while(top >= t && cross(res[top-2], res[top-1], p[i]) < 0)
            top--;
        res[top++] = p[i];
    }
    double ans = 0;
    for(i = 0; i < top - 1; i++)
        ans += dis(res[i], res[i+1]);
    return len * 1.000 - ans;
}
int main()
{
    int i, j, ca = 1;
    int val, num, tree, len, x;
    //损失的价值val, 没砍掉的树的个数num,砍掉的树的个数tree
    //砍掉一些树所能用的长度len, 最小砍掉树的个数x
    double rest;
    // 剩余量rest
    point pp[17];
    while ( ~scanf("%d", &n) && n)
    {
        for(i = 0; i < n; i++)
            scanf("%d%d%d%d", &d[i].x, &d[i].y, &d[i].v, &d[i].l);
            
        min_n = n+1; min_v = inf; rest = 0;
        
        for(i = 0; i < (1<<n); i++)
        {
            len = val = num = tree = 0;
            for(j = 0; j < n; j++)
            {
                vis[j] = 0;
                if( i & (1<<j))
                {
                    val += d[j].v;
                    len += d[j].l;
                    tree++;
                    vis[j] = 1;
                }
                else pp[num++] = point(d[j].x, d[j].y);
            }
            if(val > min_v || ( val == min_v && min_n <= tree) )continue;
            if(len == 0 && num != 1) continue;
        
            
            double ans = graham(pp, num, len);
            if(ans >= 0)
            {
                min_v = val;
                min_n = tree;
                rest = ans;
                 x = 0;
                for(j = 0; j < n; j++)
                    if(vis[j]) con[x++] = j;
            }
        }
        printf("Forest %d\nCut these trees:", ca++);
        for(j = 0; j < x; j++)
            printf(" %d", con[j]+1);
        printf("\nExtra wood: %.2f\n\n", rest);
    }
    return 0;
}

 

posted @ 2012-09-01 20:21  To be an ACMan  Views(234)  Comments(0Edit  收藏  举报