凸包,题终于过了~

B - Wall

题意:

给出平面上若干个点的坐标,任务是建一个环形围墙,把所有的点围在里面,且距所有点的距离不小于l,要求曲线长度最短,求围墙的最小长度。

思路:

很容易得出答案就是凸包周长+以l为半径的圆的周长。

使用graham扫描法,先在点集中找到最左下的点,然后将其余点相对于基准点极角排序,初始将排完序后的前两个点入栈,每次取出栈中两个点,与当前点判断,构成的角向内凹则不是凸包上点,向外凹(通过叉积判断)则为凸包上点,入栈。

代码:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn = 1000;
const double pi = 3.14159;
struct point {
    int x, y;    
};
point p[maxn + 10];
int stack[maxn + 10],top;
int n, l;

int cross(point p0, point p1, point p2)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
double dis(point p1, point p2)
{
    return sqrt((double)(p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
}
bool cmp(point p1, point p2)
{
    int tmp = cross(p[0], p1, p2);
    if (tmp > 0) return true;
    else if(tmp==0 && dis(p[0], p1) < dis(p[0], p2))
        return true;
    else return false;
}
void init()
{
    int k;
    cin >> p[0].x >> p[0].y;
    k = 0;
    for (int i = 1; i < n; i++) {
        cin >> p[i].x >> p[i].y;
        if (p[i].y < p[k].y || (p[i].y == p[k].y&&p[i].x < p[k].x)) {
            k = i;
        }
    }
    swap(p[k], p[0]);
    sort(p + 1, p + n, cmp);
}
void graham()
{
    if (n == 1) { top = 0; stack[0] = 0; }
    if (n == 2) {
        top = 1;
        stack[0] = 0;
        stack[1] = 1;
    }
    if (n > 2) {
        for (int i = 0; i <= 1; i++) stack[i] = i;
        top = 1;
        for (int i = 2; i < n; i++) {
            while (top > 0 && cross(p[stack[top - 1]], p[stack[top]], p[i]) <= 0) top--;
            top++;
            stack[top] = i;

        }
    }
}

int main()
{
    int t;
    cin >> t;
    for(int j=1;j<=t;j++) {
        cin >> n >> l;
        init();
        graham();
        double ans = 0;
        for (int i = 0; i < top; i++) {
            ans += dis(p[stack[i]], p[stack[i + 1]]);
        }
        ans += dis(p[stack[0]], p[stack[top]]);
        ans += 2 * pi*l;
        cout << (int)(ans+0.5) << endl;
        if (j != t) cout << endl;
    }
}

 

A - Beauty Contest

题意:

给定平面上的一些散点集,求最远两点距离的平方值。

思路:

凸包后再通过旋转卡壳找出最远的一对点。由于暴力找点需要n²的复杂度,因此使用旋转卡壳,可以依次枚举每条边求得距离这条最远的顶点,然后计算这个顶点到边两个端点的距离并取较大的一个,当枚举的边逆时针旋转时,最远点也是跟着逆时针变化,这样我们可以不用每次枚举所有的顶点,直接从上次的最远点开始继续计算即可,此时复杂度为O(n)。

代码:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn = 50000;
struct point {
    int x, y;
};
point p[maxn + 10], stack[maxn + 10];
int top, n;

int cross(point p0, point p1, point p2)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int dis(point p1, point p2)
{
    return (p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y);
}
bool cmp(point p1, point p2)
{
    int tmp = cross(p[0], p1, p2);
    if (tmp > 0) return true;
    else if (tmp == 0 && dis(p[0], p1) < dis(p[0], p2))
        return true;
    else return false;
}
void init()
{
    int k;
    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, cmp);
}
void graham()
{
    p[n] = p[0];
    for (int i = 0; i <= 1; i++) stack[i] = p[i];
    top = 1;
    for (int i = 2; i < n; i++) {
        while (top > 0 && cross(stack[top - 1], stack[top], p[i]) <= 0) top--;
        stack[++top] = p[i];
    }
}
int rotating()
{
    int max_dis = 0;
    stack[top + 1] = stack[0];
    int j = 2;
    for (int i = 1; i <= top; i++) {
        while (cross(stack[i + 1], stack[i], stack[j + 1]) < cross(stack[i + 1], stack[i], stack[j]))
        {
            j = (j + 1) % (top + 1);
        }
        max_dis = max(max_dis, max(dis(stack[i], stack[j]), dis(stack[i + 1], stack[j])));
    }
    return max_dis;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while (cin >> n) {
        for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;
        if (n == 2) cout << dis(p[0], p[1]) << endl;
        else {
            init();
            graham();
            int ans = rotating();
            cout << ans << endl;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/komorabi/p/10163002.html