POJ 1873 The Fortified Forest 凸包+枚举

原创 2012年03月27日 09:39:56

题意:一个人有好多树,这些树有坐标,有价值,以及砍下这颗树能造多长的篱笆。

现在他要保护自己的树不被别人砍,就需要用篱笆把树围起来,但是需要从自己的树中砍下来几棵树造成篱笆,所以问题就来了,如何砍最少价值的树把剩余的树围起来。如果价值一样,就找砍树数量少的。


看到这道题的数据范围我就笑了,直接指数级别的枚举就行了。然后求凸包。


/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 1111111
#define MAXM 104444
#define INF 100000000
#define eps 1e-7
#define L(X) X<<1
#define R(X) X<<1|1
using namespace std;
typedef double T;
struct POINT
{
  T x;
  T y;
  POINT() : x(0), y(0) {};
  POINT(T _x_, T _y_) : x(_x_), y(_y_) {};
};
POINT p[555], s[555];
T x[555], y[555],  l[555];
int v[555];
T DIS(const POINT & a, const POINT & b)
{
  return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
T CROSS(const POINT & a, const POINT & b, const POINT & o)
{
  return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}
bool cmp(const POINT & A, const POINT & B)
{
    T CR = CROSS(A, B, p[0]);
    if(CR > 0) return true;
    if(CR == 0) return DIS(A, p[0]) < DIS(B, p[0]);
    return false;
}
struct ant
{
    int a[18];
    int cnt, v;
    double len;
    void init(){ cnt = 0; len = 0; v = 0;}
};
int main()
{
    int n;
    int cas = 0;
    while(scanf("%d", &n) != EOF && n)
    {
        if(cas) printf("\n");
        for(int i = 0; i < n; i++)
            scanf("%lf%lf%d%lf", &x[i], &y[i], &v[i], &l[i]);
        int bd = (1 << n);
        ant ans;
        ans.init();
        ans.v = INF;
        T fk = 0;
        for(int j = 0; j < bd; j++)
        {
            int cnt = 0;
            int ti = j;
            ant tx;
            tx.init();
            int tn = 0;
            double need = 0;
            while(cnt < n)
            {
                if(ti & 1)
                {
                    tx.a[tx.cnt ++] = cnt;
                    tx.len += l[cnt];
                    tx.v += v[cnt];
                }
                else
                {
                    p[tn].x = x[cnt];
                    p[tn++].y = y[cnt];
                    need += l[cnt];
                }
                ti >>= 1;
                cnt++;
            }
            T xx = INF, yy = INF;
            int tmp;
            //for(int i = 0; i < tx.cnt; i++)
            //printf("%d ", tx.a[i]);
            //printf("\n");
            for(int i = 0; i < tn; i++)
            {
                //printf("ss %.3f %.3f\n", p[i].x, p[i].y);
                if(p[i].x < xx || p[i].x == xx && p[i].y < yy)
                {
                    xx = p[i].x;
                    yy = p[i].y;
                    tmp = i;
                }
            }
            double cir = 0;
            if(tn == 0 || tn == 1) cir = 0;
            else if(tn == 2)  cir = 2.0 *sqrt(DIS(p[0], p[1]));
            else{
                int top;
                swap(p[0], p[tmp]);
                sort(p + 1, p + tn, cmp);
                s[0] = p[0];
                s[1] = p[1];
                s[2] = p[2];
                top = 2;
                for(int i = 3; i < tn; i++)
                {
                    while(CROSS(p[i], s[top], s[top - 1]) > 0 && top > 1)
                    top--;
                    s[++top] = p[i];
                }
                for(int i = 0; i < top; i++)
                        cir +=sqrt(DIS(s[i], s[i + 1]));
                cir += sqrt(DIS(s[0], s[top]));
            }
            if(tx.len - cir > eps)
            {
                if(ans.v > tx.v)
                {
                    ans = tx;
                    fk = tx.len - cir;
                }
                else if(ans.v  == tx.v && ans.cnt > tx.cnt)
                {
                    ans = tx;
                    fk = tx.len - cir;
                }
            }
        }
        printf("Forest %d\nCut these trees:", ++cas);
        for(int i = 0; i < ans.cnt; i++)
        printf(" %d", ans.a[i] + 1);
        printf("\nExtra wood: %.2f\n", fk);
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ 1873 The Fortified Forest (凸包,状态压缩枚举)

题目链接:http://poj.org/problem?id=1873 题意:给出一些树,每棵树有坐标,高度,以及价值,要求砍掉一些树,用那些木材,将其它树围起来,要求花最小的代价,代价相同...
  • Strokess
  • Strokess
  • 2016年09月01日 18:04
  • 249

poj 1873 The Fortified Forest (暴力搜索+凸包求周长)

The Fortified Forest Time Limit: 1000MS   Memory Limit: 30000KB   64bit IO Format: %I64d & %I64u...
  • qq397470071
  • qq397470071
  • 2013年07月23日 20:33
  • 346

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

RT,注意考虑凸包点数小于3的情况 View Code #include #includestring.h> #include #include using namespace st...
  • c3568
  • c3568
  • 2013年08月29日 10:35
  • 518

POJ 1873 凸包+枚举

题意:一片森林,每棵树有坐标,做成栅栏的长度,本身价值,让求砍下任意棵树做成栅栏将剩下的树围上,要求被砍的这些树价值和最小,价值相同时要求被砍下的树最少,输出被砍的树,和做完栅栏后剩余的长度。 这题...
  • h6363817
  • h6363817
  • 2013年04月16日 11:14
  • 517

poj_1753 递归+枚举

思路是别人的,自己理解了半天,渣渣
  • yeruby
  • yeruby
  • 2014年04月08日 20:48
  • 1579

POJ 1873 凸包+枚举

题意:给你n棵树,每棵树都有它的坐标,价值,长度。现在要砍掉一些树,然后用这些树产生的木材(就是长度和)能够把其他的树围起来(剩下的树的凸包的周长),找到价值最小的解,如果价值相同,就选砍掉较少的树的...
  • u013307987
  • u013307987
  • 2015年05月21日 15:33
  • 180

POJ 1873 (枚举子集+凸包)

很久以前的 final 里的水题。。
  • u013112097
  • u013112097
  • 2014年05月28日 22:54
  • 218

poj3977 Subset(折半枚举)

题目大意: 给定N个整数组成的数列(N 思路: 如果单纯的枚举的话,这N个数分别有选和不选两种,所以一共有2^35个子集。很明显,会超时,但是我们可以将这个整数数列分成两半,可得每边最多18个,...
  • lolicon480
  • lolicon480
  • 2015年03月09日 11:39
  • 962

POJ 1050 To the Max (最大连续区间和+暴力枚举,水题)

Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is a...
  • h1021456873
  • h1021456873
  • 2015年09月10日 17:20
  • 330

51Nod 1873 初中的算术

1873 初中的算术基准时间限制:1 秒 空间限制:131072 KB Noder现在上初三了,正在开始复习中考。他每天要计算型如 (a× a× a× ⋯× a)n个a 的式子。 其中 0.0//刚...
  • qq_35776409
  • qq_35776409
  • 2017年07月19日 08:52
  • 326
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 1873 The Fortified Forest 凸包+枚举
举报原因:
原因补充:

(最多只允许输入30个字)