题解 P3829 【[SHOI2012]信用卡凸包】

题目链接

这题如果每个信用卡都不一样不知道怎么做啊……萌新求大佬私信指点迷津qaq

Solution [SHOI2012]信用卡凸包

题目大意:给定一个矩形,将其四角替换为\(\frac{1}{4}\)圆弧(也就是信用卡的样子),将这个矩形进行旋转和平移之后得到多个矩形,求凸包长

计算几何



分析:旋转什么的基本操作,我们看比较恶心的圆弧怎么算

样例一可以知道如果\(r=0\)我们直接对矩形顶点求凸包就好,如果\(r\neq0\)我们可以通过平移,将其周长转化为若干个圆心点的凸包周长加一个圆的周长

这个操作可以理解为将凸包整体向内收缩了\(r\),所以不影响正确性,然后我们直接求一个朴素凸包周长最后加上一个半径为\(r\)的圆周长即可

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 5e4 + 100;
const double pi = acos(-1),eps = 1e-4;
struct Point{
    double x,y;
}p[maxn],stk[maxn],w[4],org;
typedef Point Vector;
inline Vector operator + (Vector a,Vector b){return Vector{a.x + b.x,a.y + b.y};}
inline Vector operator - (Vector a,Vector b){return Vector{a.x - b.x,a.y - b.y};}
inline Vector rotate(Vector now,double theta){return Vector{now.x * cos(theta) - now.y * sin(theta),now.x * sin(theta) + now.y * cos(theta)};}
inline double cross(Vector a,Vector b){return a.x * b.y - a.y * b.x;}
inline double sq(double x){return x * x;}
inline double dis(Point a,Point b){return sqrt(sq(a.x - b.x) + sq(a.y - b.y));}
inline int dcmp(double x){return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1);}
inline bool operator < (Point a,Point b){
    double tmp = cross(a - org,b - org);
    if(dcmp(tmp) > 0)return true;
    else if(dcmp(tmp) == 0 && dis(org,a) < dis(org,b))return true;
    else return false;
}
istream& operator >> (istream &in,Point &x){
    in >> x.x >> x.y;
    return in;
}
ostream& operator << (ostream &out,Point &x){
    out << x.x << " " << x.y;
    return out;
}
int n,tot,top;
double a,b,r,ans;
int main(){
    ios::sync_with_stdio(false);
    cout << setiosflags(ios::fixed) << setprecision(2);
    cin >> n;
    cin >> a >> b >> r;
    w[0] = Vector{-0.5 * b + r,0.5 * a - r};
    w[1] = Vector{0.5 * b - r,0.5 * a - r};
    w[2] = Vector{0.5 * b - r,-0.5 * a + r};
    w[3] = Vector{-0.5 * b + r,-0.5 * a + r};
    for(int i = 1;i <= n;i++){
        Point from;double theta;
        cin >> from >> theta;
        for(int i = 0;i < 4;i++)
            p[++tot] = from + rotate(w[i],theta);
    }
    org = p[1];
    for(int i = 1;i <= tot;i++)
        if(p[i].y < org.y || (p[i].y == org.y && p[i].x < org.x))org = p[i];
    sort(p + 1,p + 1 + tot);
    stk[++top] = p[1];
    for(int i = 2;i <= tot;i++){
        while(top > 1 && dcmp(cross(stk[top - 1] - stk[top],p[i] - stk[top])) >= 0)top--;
        stk[++top] = p[i];
    }
    stk[top + 1] = p[1];
    for(int i = 1;i <= top;i++)ans += dis(stk[i],stk[i + 1]);
    ans += pi * 2 * r;
    cout << ans << '\n';
    return 0;
}

原文地址:https://www.cnblogs.com/colazcy/p/12064538.html

时间: 2024-10-12 15:59:23

题解 P3829 【[SHOI2012]信用卡凸包】的相关文章

P3829 [SHOI2012]信用卡凸包

传送门 不难发现这个信用卡凸包的周长就是一个整圆的周长再加上所有的四个边角的点形成的凸包 于是直接把这个凸包求出来即可 还有就是一个向量\((x,y)\)逆时针旋转\(t\)度之后坐标是\((x*cos(t)-y*sin(t),x*sin(t)+y*cos(t))\)(话说原来这玩意儿还有公式的么--) //minamoto #include<bits/stdc++.h> #define inf 1e10 #define eps 1e-10 #define fp(i,a,b) for(regi

Luogu-3829 [SHOI2012]信用卡凸包

这道题的转化很巧妙,可以把信用卡四个角的圆心看做平面上的点来做凸包,\(ans\)就是凸包周长加上一个圆的周长 // luogu-judger-enable-o2 #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e5+100; const double Pi=3.141592653589793

SHOI2012 信用卡凸包

题意: 题目链接 题目大意: 给出n个四角为pi/4的圆弧的类矩形,求它们凸包的周长 思路: 乍看似乎没有思路,但注意到r=0时求的是一个裸的凸包 考虑当r不等于0时,我们先按之前的方法求出凸包周长 然后对于每个拐点求其角度,而后求出这段圆弧长,累加即可... for(int i=1;i<=m;++i) { ans+=(q[i]-q[i+1]).dist(); double cs=((q[i]-q[i+1])*(q[i+2]-q[i+1]))/(q[i]-q[i+1]).dist()/(q[i+

bzoj2829 信用卡凸包

2829: 信用卡凸包 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special Judge Submit: 226  Solved: 102 [Submit][Status][Discuss] Description Input Output Sample Input 2 6.0 2.0 0.0 0.0 0.0 0.0 2.0 -2.0 1.5707963268 Sample Output 21.66 HINT 本样例中的2张信用卡的轮廓在上图中

【题解】二维凸包

[题解]二维凸包 呵呵呵复习一下这个东西免得做到计算几何连暴力都不会嘤嘤嘤 免得到时候写斜率优化结果凸包不会了嘤嘤嘤 数学走起: \[ \vec{a}=(x_1,y_1),\vec{b}=(x_2,y_2) \shadow_{|\vec{a} \times\vec{b}|}=x_1y_2-x_2y_1 \] 根据右手螺旋定则.\(shadow\)是我乱搞的符号,虽然我搞不懂为什么是这样,但是这个应该和\(\sin(0.5\pi)=1,\sin0=0\)有关,就不纠结了,也比较好记. 遵循\(an

【计算几何】【凸包】bzoj2829 信用卡凸包

http://hzwer.com/6330.html #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 100001 #define EPS 0.00000001 typedef double db; const db PI=acos(-1.0); struct Point{db x,y;}p[N<<2],bao[N<<2]; b

POJ 3348 Cows(凸包面积)

Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7515   Accepted: 3418 Description Your friend to the south is interested in building fences and turning plowshares into swords. In order to help with his overseas adventure, they are f

【BZOJ1069】【SCOI2007】最大土地面积 凸包 单调性

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46591735"); } 题解: 先求凸包,然后: 枚举点 i ,然后对于 点 j 得到的 i 与 j (有序) 中间的点,以及 j 与 i (有序) 中间的点,都是单调的. 代码: #include <cmat

bzoj1069: [SCOI2007]最大土地面积 凸包+旋转卡壳求最大四边形面积

在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. 题解:先求出凸包,O(n)枚举旋转卡壳,O(n)枚举另一个点,求最大四边形面积 /************************************************************** Problem: 1069 User: walfy Language: C++ Result: Accepted Time:892 ms Memory:1360 kb ****