1 条题解
-
0
题意分析
给你n棵树,每棵树都有它的坐标,价值,长度。现在要砍掉一些树,然后用这些树产生的木材(就是长度和)能够把其他的树围起来(剩下的树的凸包的周长),找到价值最小的解,如果价值相同,就选砍掉较少的树的解
解题思路
就是枚举+求凸包周长,需要有个剪纸就是如果当前的价值比当前最小价值大,那么这个情况肯定是不行的,不然会T
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<queue> #include<list> using namespace std; const double INF = 1e200; const double EP = 1e-10; const int maxn = 16; const double PI = acos(-1); struct POINT {///点 定义 double x; double y; int v, l; POINT(double a = 0, double b = 0, int vv = 0, int ll = 0) { x = a; y = b; v = vv; l = ll; } }; struct SEGMENT {///line segment///线段 定义 POINT s; POINT e; SEGMENT(POINT a, POINT b) { s = a; e = b; } SEGMENT() {} }; struct LINE {///ax + by + c = 0&&a >= 0///一般式 double a; double b; double c; LINE(double da, double db, double dc) { a = da; b = db; c = dc; } LINE(double x1, double y1, double x2, double y2) {///根据两个点求出一般式 a = y1 - y2; b = x2 - x1; c = x1 * y2 - x2 * y1; if (a < 0) { a *= -1; b *= -1; c *= -1; } } }; double multiply(POINT sp, POINT ep, POINT op) {///向量op->sp X op->ep的叉乘,小于0:ep在op->sp顺时针方向//大于0:ep在op->sp逆时针方向//等于0:三点共线 return ((sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y)); } double dotmultiply(POINT p1, POINT p2, POINT p0) { return ((p1.x - p0.x) * (p2.x - p0.x) + (p1.y - p0.y) * (p2.y - p0.y)); } bool online(SEGMENT l, POINT p) {///判断点是否在线段上 return ((multiply(l.e, p, l.s) == 0) && (((p.x - l.s.x) * (p.x - l.e.x)) <= 0) && (((p.y - l.s.y) * (p.y - l.e.y)) <= 0)); } bool intersect(SEGMENT u, SEGMENT v) {///两线段相交(包括端点),返回true return ((max(u.s.x, u.e.x) >= min(v.s.x, v.e.x)) && (max(v.s.x, v.e.x) >= min(u.s.x, u.e.x)) && (max(u.s.y, u.e.y) >= min(v.s.y, v.e.y)) && (max(v.s.y, v.e.y) >= min(u.s.y, u.e.y)) && (multiply(v.s, u.e, u.s) * multiply(u.e, v.e, u.s) >= -EP) && (multiply(u.s, v.e, v.s) * multiply(v.e, u.e, v.s) >= -EP)); } bool intersect_a(SEGMENT u, SEGMENT v) {///两线段相交(不包括端点) return ((intersect(u, v)) && !online(u, v.s) && !online(u, v.e) && !online(v, u.e) && !online(v, u.s)); } int lineintersect(LINE l1, LINE l2, POINT& p) {///求两直线交点,有交点返回1和交点,没有返回0,重合返回2 double d = l1.a * l2.b - l2.a * l1.b; double d2 = l1.a * l2.c - l2.a * l1.c; double d3 = l1.b * l2.c - l2.b * l1.c; if (fabs(d) < EP && fabs(d2) < EP && fabs(d3) < EP)return 2; p.x = (l2.c * l1.b - l1.c * l2.b) / d; p.y = (l2.a * l1.c - l1.a * l2.c) / d; if (fabs(d) < EP)return 0; return 1; } double dis(POINT a, POINT b) {///求两点距离 return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } ///****************凸包************************************** int top;///凸包的顶点个数 POINT p[maxn], stack[maxn]; bool top_cmp(POINT a, POINT b) { double k = multiply(a, b, p[0]); if (k > 0)return 1; if (k < 0)return 0; return dis(a, p[0]) < dis(b, p[0]); } void graham(int n) { top = 1; int k = 0; for (int i = 1; i < n; i++) if (p[i].y < p[k].y || ((p[i].y == p[k].y) && (p[i].x < p[k].x))) k = i; swap(p[0], p[k]); sort(p + 1, p + n, top_cmp); stack[0] = p[0], stack[1] = p[1]; for (int i = 2; i < n; i++) { while (top >= 1 && multiply(p[i], stack[top], stack[top - 1]) >= 0)top--; stack[++top] = p[i]; } } ///******************凸包结束**************** double get_area(int n, POINT v[]) {///*********多边形面积 double ans; if (n < 3)return 0; ans = (double)(v[0].y * (v[n - 1].x - v[1].x)); for (int i = 1; i < n; i++) { ans += (double)(v[i].y * (v[i - 1].x - v[i + 1].x)); } return ans / 2.0; } double get_len(int n, POINT v[]) { double ans = dis(v[0], v[n - 1]); for (int i = 0; i < n - 1; i++) { ans += dis(v[i], v[i + 1]); } return ans; } ///********************************************************************************* POINT all[maxn]; int main() { //freopen("in.txt","r",stdin); int n; int cas = 1; while (~scanf("%d", &n)) { if (n == 0)break; for (int i = 0; i < n; i++) { double x, y, v, l; scanf("%lf%lf%lf%lf", &x, &y, &v, &l); all[i].x = x; all[i].y = y; all[i].v = v; all[i].l = l; } double min_val = 10000000; double min_tree = 10000; double num_wood = 0; int status = 0; for (int i = 1; i < (1 << n) - 1; i++) { int tot = 0;///the number of tree don't used double val = 0; double wood = 0; for (int j = 0; j < n; j++) { if (((1 << j) & i) == 0) { p[tot++] = all[j]; } else { val += all[j].v;//cout<<val<<endl; wood += all[j].l; } }//cout<<tot<<endl; if (val > min_val)continue; double len = 0; if (tot == 1)len = 0; else if (tot == 2)len = 2 * dis(p[0], p[1]); else { graham(tot); len = get_len(top + 1, stack); } if (len <= wood) { if (val < min_val) { min_val = val; min_tree = n - tot; num_wood = wood - len; status = i; } else if (val == min_val && min_tree > n - tot) { min_tree = n - tot; num_wood = wood - len; status = i; } } } printf("Forest %d\nCut these trees:", cas++); bool used[maxn] = { 0 }; for (int i = 0; i < n; i++) { if (((1 << i) & status))used[i] = 1; } for (int i = 0; i < n; i++) if (used[i]) { printf(" %d", i + 1); } printf("\nExtra wood: %.2f\n\n", num_wood + EP); } return 0; }
- 1
信息
- ID
- 874
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者