1. 程式人生 > >HDU 1392 Surround the Trees(凸包)題解

HDU 1392 Surround the Trees(凸包)題解

code esp pos con clas tac span bool swa

題意:給一堆二維的點,問你最少用多少距離能把這些點都圍起來

思路:

凸包:

我們先找到所有點中最左下角的點p1,這個點絕對在凸包上。接下來對剩余點按照相對p1的角度升序排序,角度一樣按距離升序排序。因為凸包有一個特點,順時針走,所有線都在當前這條向量的右邊,根據這個特點我們進行判斷。我們從棧頂拿出兩個點s[top-1],s[top],所以如果s[top-1] -> p[i] 在 s[top-1] -> s[top] 左邊,那麽s[top]就不是凸包上一點,就這樣一直判斷下去。判斷左右可以用叉乘。

參考:數學:凸包算法詳解

模板(考慮n <= 2):

struct
node{ double x, y; }p[maxn], s[maxn]; int n, top; double dis(node a, node b){ return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } bool cmp(node a, node b){ double A = atan2((a.y - p[1].y), (a.x - p[1].x)); double B = atan2((b.y - p[1].y), (b.x - p[1].x));
if(A != B) return A < B; else{ return dis(a, p[1]) < dis(b, p[1]); } } double cross(node a, node b, node c){ //(a->b)X(a->c) return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); } void solve(){ int pos = 1; for(int i = 2; i <= n; i++){
if(p[i].y < p[pos].y || (p[i].y == p[pos].y && p[i].x < p[pos].x)){ pos = i; } } swap(p[1], p[pos]); sort(p + 2, p + n + 1, cmp); s[0] = p[1], s[1] = p[2]; top = 1; for(int i = 3; i <= n; i++){ while(top >= 1 && cross(s[top - 1], p[i], s[top]) >= 0){ //向左轉出棧 top--; } s[++top] = p[i]; } }

代碼:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 150 + 10;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct node{
    double x, y;
}p[maxn], s[maxn];
int n, top;
double dis(node a, node b){
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool cmp(node a, node b){
    double A = atan2((a.y - p[1].y), (a.x - p[1].x));
    double B = atan2((b.y - p[1].y), (b.x - p[1].x));
    if(A != B) return A < B;
    else{
        return dis(a, p[1]) < dis(b, p[1]);
    }
}
double cross(node a, node b, node c){   //(a->b)X(a->c)
    return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
void solve(){
    int pos = 1;
    for(int i = 2; i <= n; i++){
        if(p[i].y < p[pos].y || (p[i].y == p[pos].y && p[i].x < p[pos].x)){
            pos = i;
        }
    }
    swap(p[1], p[pos]);
    sort(p + 2, p + n + 1, cmp);
    s[0] = p[1], s[1] = p[2];
    top = 1;
    for(int i = 3; i <= n; i++){
        while(top >= 1 && cross(s[top - 1], p[i], s[top]) >= 0){ //向左轉出棧
            top--;
        }
        s[++top] = p[i];
    }
}
int main(){
    while(~scanf("%d", &n) && n){
        for(int i = 1; i <= n; i++){
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        if(n == 1){
            printf("0.00\n");
            continue;
        }
        if(n == 2){
            printf("%.2lf\n", dis(p[1], p[2]));
            continue;
        }
        solve();
        double ans = 0;
        for(int i = 0; i < top; i++){
            ans += dis(s[i], s[i + 1]);
        }
        ans += dis(s[top], s[0]);
        printf("%.2lf\n", ans);
    }
    return 0;
}

HDU 1392 Surround the Trees(凸包)題解