• POJ 1873 The Fortified Forest (凸包 + 暴力枚举)


    题目:传送门

    题意:有 n 棵树,第 i 棵树位于点 (xi, yi),有 vi 的价值, Li 的长度,现在你需要建一个篱笆,把所有树围起来,你只能通过砍掉其中的一些树来获得建篱笆的材料。现在问你能顺利建成篱笆需要砍掉的树的价值最小是多少,如果有多种价值一样小的方案,输出砍掉的树数目最少的情况。

    2 <= n <= 15

    思路:n很小,可以直接暴力枚举所有状态,如果二进制位上是1,代表砍掉这颗树。然后,剩下的树,要建篱笆将它们包围起来,且篱笆的周长要尽可能小,那就是求凸包周长了。

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 5e4 + 5;
    
    struct Point {
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) { } /// 构造函数
    };
    
    typedef Point Vector;
    /// 向量+向量=向量, 点+向量=向量
    Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
    ///点-点=向量
    Vector operator - (Point A, Point B) { return Vector(A.x - B.x, A.y - B.y); }
    ///向量*数=向量
    Vector operator * (Vector A, double p) { return Vector(A.x * p, A.y * p); }
    ///向量/数=向量
    Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
    
    const double eps = 1e-10;
    int dcmp(double x) {
        if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
    }
    
    bool operator < (const Point& a, const Point& b) {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
    
    bool operator == (const Point& a, const Point &b) {
        return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    }
    
    double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } /// 点积
    double Length(Vector A) { return sqrt(Dot(A, A)); } /// 计算向量长度
    double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } /// 向量A、B夹角
    double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; } /// 叉积
    
    struct note {
        Point p;
        int V, L;
    }a[N];
    
    Point P[N], Q[N];
    
    int ConvexHull(Point* p, int n, Point* ch) { /// 求凸包
        sort(p, p + n);
        int m = 0;
        rep(i, 0, n - 1) {
            while(m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
            ch[m++] = p[i];
        }
        int k = m;
        dep(i, 0, n - 2) {
            while(m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
            ch[m++] = p[i];
        }
        if(n > 1) m--;
        return m;
    }
    
    int ANS[N];
    
    int main() {
    
        int n; int Cas = 0;
        while(scanf("%d", &n) && n) {
    
            rep(i, 0, n - 1) scanf("%lf %lf %d %d", &a[i].p.x, &a[i].p.y, &a[i].V, &a[i].L);
    
            int ans_val = 10000000, ans_num = 0;
            double ans_dis = 0.0;
    
            rep(i, 0, (1 << n) - 1) { /// 暴力枚举
    
                int tmp_val = 0, tmp_num = 0;
                double tmp_dis = 0;
    
                rep(j, 0, n - 1) {
                    if((i >> j) & 1) tmp_dis += a[j].L, tmp_val += a[j].V;
                    else P[tmp_num++] = a[j].p;
                }
    
                tmp_num = ConvexHull(P, tmp_num, Q);
    
                double need_dis = 0.0;
                rep(j, 0, tmp_num - 1) {
                    need_dis += Length(Q[(j + 1) % tmp_num] - Q[j]);
                }
    
                if(dcmp(tmp_dis - need_dis) >= 0) {
                    if(tmp_val < ans_val) {
                        ans_val = tmp_val;
                        ans_num = 0;
                        rep(j, 0, n - 1) {
                            if((i >> j) & 1) ANS[ans_num++] = j + 1;
                        }
                        ans_dis = tmp_dis - need_dis;
                    }
                    else if(tmp_val == ans_val) {
                        if(tmp_num < ans_num) {
                            rep(j, 0, n - 1) {
                                if((i >> j) & 1) ANS[ans_num++] = j + 1;
                            }
                            ans_dis = tmp_dis - need_dis;
                        }
                    }
                }
    
            }
    
            printf("Forest %d
    ", ++Cas);
            printf("Cut these trees:");
            rep(i, 0, ans_num - 1) printf(" %d", ANS[i]); puts("");
            printf("Extra wood: %.2f
    ", ans_dis);
            puts("");
        }
    
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    sql 修改字段小记
    (转)web.config 为某个单独页面设置编码格式
    gb2312编码提交url乱码解决
    Windows 8上强制Visual Studio以管理员身份运行
    new、delete用法(一)
    把varchar转换为int 然后进行排序
    linq 整体修改字段
    游标用法
    分组并赋值
    读取xml
  • 原文地址:https://www.cnblogs.com/Willems/p/12423740.html
Copyright © 2020-2023  润新知