pku1113ウォール凸包(アンドリュー・アルゴリズム版)

题目链接
制限時間:1000msのメモリ制限:10000K
総提出:42823受理:14602
説明

むかしむかし王の城の周りに壁を構築するために彼のチーフアーキテクトを命じ貪欲王がありました。王は彼が完全な形と素敵な背の高い塔の美しいレンガの壁を構築するために彼の建築家の提案に耳を傾けないであろうと、とても貪欲でした。代わりに、彼は石と労働の最低額を使用して、全体の城の周りに壁を構築するために注文したが、壁が一定の距離よりも城に近づくべきではないことを要求しました。王はこれらの要件を満たすために絶対に必要であったよりArchitectは、壁を構築するために、より多くのリソースを使用していたことを発見した場合、その後、建築家は、彼の頭を失うことになります。また、彼は一度壁を構築するために必要なリソースの正確な量を一覧壁の計画を紹介する建築家を要求しました。

あなたの仕事は、彼は王の要件を満たすために、城の周りに構築することができ、壁の最小の可能な長さを見つけるプログラムを書くことで、自分の頭を救うために貧しいArchitectを支援することです。

タスクはやや王の城は、多角形の形状をしており、平らな地面の上に位置していることを、事実によって簡素化されます。アーキテクトは、すでに直交座標系を確立していると正確に足のすべての城の頂点の座標を測定しました。
入力

入力ファイルの最初の行は、スペースで区切られた2つの整数N及びLを含有します。N(3 <= N <= 1000)王の城の頂点の数であり、L(1 <= L <= 1000)王は城に近接する壁を可能にする足の最小数です。

次のNラインは、時計回り順に城の頂点の座標を記述する。各ラインは、i番目の頂点の座標を表す2つの整数Xi及びイースペースで区切られた(-10000 <=西、李<= 10000)を含有します。すべての頂点は異なっており、城の側面は頂点以外のどこにも交差していません。
出力

出力ファイルに王の要件を満たすために城を中心に構築することができ、足で壁の最小の可能な長さを表す単一の番号を書きます。浮動小数点数はまだ発明されていないので、あなたは、王の足の整数を提示しなければなりません。しかし、あなたは王が見積もりに大きな誤差を許容しないので、それは、(1フィートは12インチに等しい)8インチに正確であることを、このように結果を丸める必要があります。

サンプル入力

100 9
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200

サンプル出力

1628

ヒント

結果は切り上げられます

問題の意味:凸包境界プラス周周囲を求めて

コード:

#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <climits>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e4 + 7;
const ll MAXM = 1e3 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
struct node
{
    double x, y;
} a[MAXN];
node sta[MAXN];
int cnt = 0;
bool cmp(node x, node y)
{
    if (x.x == y.x)
        return x.y < y.y;
    return x.x < y.x;
}
double ccw(node a, node b, node c) //利用叉积判断方向(c点是否在ab向量的逆时针方向)
{
     return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x)<0;
    /* 小于0说明顺时针方向 */
}
void convex(int n, node a[])
{
    sort(a, a + n, cmp);
    cnt = 0;
    for (int i = 0; i < n; i++) //计算上半个凸包
    {
        /*如果点数有两个或以上且即将加入凸包的点位于凸包倒数第二点和倒数第一个点所构成的向量的逆时针位置,则删除倒数第一个点*/
        while (cnt > 1 && ccw(sta[cnt - 2], sta[cnt - 1], a[i]))
            --cnt;
        sta[cnt++] = a[i];
    }
    int k = cnt;
    for (int i = n - 2; i >= 0; --i) //计算下半个凸包
    {
        while (cnt > k && ccw(sta[cnt - 2], sta[cnt - 1], a[i]))
            --cnt;
        sta[cnt++] = a[i];
    }
    if (n > 1) //对于只有一个点的包再单独判断
        --cnt;
}
double dis(node x, node y)
{
    return sqrt((y.y - x.y) * (y.y - x.y) + (y.x - x.x) * (y.x - x.x));
}
int main()
{
    int N, L;
    while (~scanf("%d%d", &N, &L))
    {
        for (int i = 0; i < N; i++)
            scanf("%lf%lf", &a[i].x, &a[i].y);
        convex(N, a);
        double ans = 2 * pi * L;
        for (int i = 1; i < cnt; i++)
            ans += dis(sta[i], sta[i - 1]);
        ans += dis(sta[0], sta[cnt - 1]);
        printf("%d\n", (int)(ans+0.5));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/graytido/p/11121603.html