POJ1518、 UVA1531 - Problem Bee(几何+贪心)

Imagine a perfectly formed honeycomb, spanning the infinite Cartesian plane. It is an interlocking grid composed of congruent equilateral hexagons. One hexagon is located so that its center is at the origin and has two corners on the X-axis. A bee must be very careful about how it travels in order not to get lost in the infinite plane. To get from an arbitrary point A to another arbitrary point B, it will first head from A to the exact center of the hexagon in which A is located. Then, it will travel in a straight line to the exact center of an adjacent hexagon. It will move from center to adjacent center until it has reached the hexagon containing point B. At the destination hexagon, it will move from the center to point B. In all cases, the bee will take a path of minimal distance that obeys the rules. The figure below demonstrates one possible minimal path from point A to point B.

graphic of a honeycomb

Input

Input will be in the form of 5 floating point numbers per line. The first number will be the length, in centimeters, of the sides of the hexagons. The next two numbers will be the x and y coordinates of point A, followed by the x and y coordinates of point B. The input will be terminated by a line containing five zeroes. Neither point A nor point B will ever be exactly on a border between hexagons.

Output

For each line of the input, output the minimum length of a path from point A to point B, to the nearest 0.001 centimeters.

Sample Input

1.0 -3.2 2.2 3.3 0
9 1 4 5 1
0.1 0.09 0 0.21 0
0 0 0 0 0

Sample Output

7.737
5.000
0.526


题意:给定蜂窝长度,起点A和起点B,蜜蜂移动要从A移动到对应的六边形中心,然后从一个六边形中心移动到另一个六边形中心,最后在从六边形中心移动到B,注意如果AB在同一中心,直接A移动到B。

思路:竖直方向和水平方向多的肯定是要移动的段数,那么问题就变成找A和B的中心,直接找点对应的X,Y坐标是第几个六边形,注意如果在边上要处理一下,最后判断周围6个是否有比它距离更近的六边形中心,确定中心后,路径就很好计算了,

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define max(a,b) ((a)>(b)?(a):(b))
const double pi = acos(-1.0);
const int d[6][2] = {{0, 2}, {0, -2}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
double l, xa, ya, xb, yb, hd, wd;
int xan, yan, xbn, ybn;

double dis(double x1, double y1, double x2, double y2) {
    return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}

void tra(int &x, int &y, double xa, double ya) {
    if (x % 2) {
	if (y % 2 == 0) {
	    y++;
	}
    }
    else {
	if (y % 2) {
	    y++;
	}
    }
    int minx = x, miny = y;
    double mind = dis(x * wd, y * hd, xa, ya);
    for (int i = 0; i < 6; i++) {
	double xx = (d[i][0] + x) * wd;
	double yy = (d[i][1] + y) * hd;
	if (mind > dis(xx, yy, xa, ya)) {
	    minx = d[i][0] + x;
	    miny = d[i][1] + y;
	    mind = dis(xx, yy, xa, ya);
	}
    }
    x = minx; y = miny;
}

void init() {
    hd = sin(pi/3) * l;
    wd = l + l / 2;
    xan = xa / wd;
    yan = ya / hd;
    xbn = xb / wd;
    ybn = yb / hd;
    tra(xan, yan, xa, ya); tra(xbn, ybn, xb, yb);
}

double solve() {
    if (xan == xbn && yan == ybn)
	return dis(xa, ya, xb, yb);
    int xx = abs(xbn - xan), yy = abs(ybn - yan);
    double ans = dis(xa, ya, xan * wd, yan * hd) + dis(xb, yb, xbn * wd, ybn * hd) + xx * sin(pi/3) * 2 * l;
    if (yy > xx)
	ans += (yy - xx) * l * sqrt(3) / 2;
    return ans;
}

int main() {
    while (~scanf("%lf%lf%lf%lf%lf", &l, &xa, &ya, &xb, &yb) && l || xa || ya || xb || yb) {
	init();
	printf("%.3lf\n", solve());
    }
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值