Rotational Painting(hdu 3685 凸包+多边形重心 模板题

Posted ydw--

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rotational Painting(hdu 3685 凸包+多边形重心 模板题相关的知识,希望对你有一定的参考价值。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3685

ac代码:

技术图片
#include<bits/stdc++.h>
#define ll long long
#define maxn 50010
using namespace std;
const double zero=1e-8;
struct node
{
    double x,y;
}p[maxn],q[maxn];//p保存原始点,q保存凸包的点
bool operator <(node a,node b)
{
    if(fabs(a.y-b.y)>zero)//误差
        return (a.y<b.y);
    else if(fabs(a.x-b.x)>zero)
        return (a.x<b.x);
    return false;
}
double det(node a,node b,node c)//叉积
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double dot(node a,node b,node c)//点积
{
    return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
}
double det3(node a,node b,node c)//叉积的三出口函数
{
    double d=det(a,b,c);
    if(fabs(d)<=zero)return 0;
    if(d<0)return-1;
    return 1;
}
void c_h_add(node li[],int &m0,int base,node p)
{
    while(m0>base&&det3(li[m0-2],li[m0-1],p)<=0)--m0;
    li[m0]=p;
    m0++;
}
node c[maxn];
int n,m;
void c_h(int &m0)
{
    int i;
    for(i=0;i<n;i++)
        q[i]=p[i];
    sort(q,q+n);
    m0=0;
    for(i=0;i<n;i++)c_h_add(c,m0,1,q[i]);
    int m1=m0;
    for(i=n-1;i>=0;i--)c_h_add(c,m0,m1,q[i]);
    for(i=0;i<m0;i++)q[i]=c[i];
    m0--;
}
bool is_big_angle(node a,node b,node c)//判断以b为顶点的角是否是直角或钝角
{
    double Lcos=dot(b,a,c);
    if(Lcos>zero)return 0;
    return 1;
}
bool check(node zx,node a,node b)//判断zx到直线ab的垂足是否在线段ab上
{
    return (!is_big_angle(zx,a,b)&&!is_big_angle(zx,b,a));
}
int main()
{
    int t,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        node o,o1;
        o.x=o.y=0;
        double s=0,s1;
        for(i=1;i<n-1;i++)
        {
            o1.x=(p[0].x+p[i].x+p[i+1].x);
            o1.y=(p[0].y+p[i].y+p[i+1].y);
            s1=det(p[0],p[i],p[i+1]);
            s+=s1;
            o.x+=o1.x*s1;
            o.y+=o1.y*s1;
        }
        o.x=o.x/s/3.0;//除3放到最后除
        o.y=o.y/s/3.0;//多边形重心
        m=0;
        c_h(m);
        int ans=0;
        for(i=0;i<m-1;i++)
        {
            if(check(o,q[i],q[i+1]))ans++;
        }
        if(check(o,q[m-1],q[0]))ans++;
        cout<<ans<<endl;
    }
    return 0;
}
View Code

求多边形重心模板:

https://www.cnblogs.com/hate13/p/4152302.html

技术图片
#include<bits/stdc++.h>
#define ll long long
#define maxn 50010
using namespace std;
const double zero=1e-8;
struct node
{
    double x,y;
}p[maxn],q[maxn];
double det(node a,node b,node c)//叉积
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int main()
{
    int t,i,j,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        node o,o1;
        o.x=o.y=0;
        double s=0,s1;
        for(i=1;i<n-1;i++)
        {
            o1.x=(p[0].x+p[i].x+p[i+1].x);
            o1.y=(p[0].y+p[i].y+p[i+1].y);
            s1=det(p[0],p[i],p[i+1]);
            s+=s1;
            o.x+=o1.x*s1;
            o.y+=o1.y*s1;
        }
        o.x=o.x/s/3.0;
        o.y=o.y/s/3.0;//多边形重心
        printf("%.3f %.3f
",o.x,o.y);
    }
    return 0;
}
View Code

求凸包模板:

https://www.cnblogs.com/wpbing/p/9456240.html

技术图片
#include<bits/stdc++.h>
using namespace std;

struct point{
    double x,y;
    point friend operator -(point a,point b)
    {return {a.x-b.x,a.y-b.y};}
}p[105],s[105];
double dis(point a,point b)
{
    point c=a-b;
    return sqrt(c.x*c.x+c.y*c.y);
}
double X(point a,point b)
{
    return a.x*b.y-a.y*b.x;
}
int cmp(point a,point b)
{
    double x=X(a-p[1],b-p[1]);
    
    if(x>0) return 1;
    if(x==0&&dis(a,p[1])<dis(b,p[1])) return 1;
    return 0;
}
double multi(point p1,point p2,point p3)
{
    return X(p2-p1,p3-p1);
}
int main()
{
    int N;
    while(scanf("%d",&N),N)
    {
        for(int i=1;i<=N;i++) cin>>p[i].x>>p[i].y;
        int k=1;
        for(int i=2;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[1],p[k]);
        sort(p+2,p+1+N,cmp);
        s[1]=p[1];
        s[2]=p[2];
        int t=2;
        for(int i=3;i<=N;i++)
        {
            while(t>=2&&multi(s[t-1],s[t],p[i])<=0) t--;
            s[++t]=p[i];
        }
        double sum=0;
        for(int i=1;i<t;i++)
        {
            sum+=dis(s[i],s[i+1]);//s[i]凸包上的每个点 sum周长
        }
        printf("%.2lf
",sum+dis(s[1],s[t]));
    }
    return 0;
}
View Code

 求凸包(有序 按逆时针或顺时针排序)

技术图片
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn=1005;
const double PI=acos(-1.0);

struct Point{
    int x,y;
    Point():x(0),y(0){}
    Point(int x,int y):x(x),y(y){}
}list[maxn];
int stack[maxn],top;

//计算叉积p0p1×p0p2
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);
}
//计算p1p2的距离
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(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
//输入,把最左下角放在list[0],并且进行极角排序
void init(int n){
    Point p0;
    scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    int k=0;
    for(int i=1;i<n;++i){
        scanf("%d%d",&list[i].x,&list[i].y);
        if((p0.y>list[i].y)||((p0.y==list[i].y)&&(p0.x>list[i].x))){
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;
    sort(list+1,list+n,cmp);
}
//graham扫描法求凸包,凸包顶点存在stack栈中
//从栈底到栈顶一次是逆时针方向排列的
//如果要求凸包的一条边有2个以上的点
//那么要将while中的<=改成<
//但这不能将最后一条边上的多个点保留
//因为排序时将距离近的点排在前面
//那么最后一条边上的点仅有距离最远的会被保留,其余的会被出栈
//所以最后一条边需要特判
void graham(int n){
    if(n==1){
        top=0;
        stack[0]=0;
        return;
    }
    top=1;
    stack[0]=0;
    stack[1]=1;
    for(int i=2;i<n;++i){
        while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) --top;
        stack[++top]=i;
    }
}
int main(){
    int n,t;
    scanf("%d",&t);
    while(t--){
        int id;
        scanf("%d %d",&id,&n);
        init(n);
        graham(n);
        printf("%d %d
",id,1+top);
        int kk=0;
        for(int i=1;i<=top;++i)
            if(list[stack[i]].y>list[stack[kk]].y||list[stack[i]].y==list[stack[kk]].y&&list[stack[i]].x<list[stack[kk]].x)kk=i;

        for(int i=kk;i>=0;i--)printf("%d %d
",list[stack[i]].x,list[stack[i]].y);
        for(int i=top;i>kk;i--)printf("%d %d
",list[stack[i]].x,list[stack[i]].y);//顺时针顺序输出每个点
        
        /*
        double res=0;//求凸包周长
    for(int i=0;i<top;++i)
        res+=dis(list[stack[i]],list[stack[i+1]]);
    res+=dis(list[stack[0]],list[stack[top]]);
    printf("%d
",(int)(res+0.5));
    */
    }
    return 0;
}
graham扫描法

 

以上是关于Rotational Painting(hdu 3685 凸包+多边形重心 模板题的主要内容,如果未能解决你的问题,请参考以下文章

Rotational Painting(hdu 3685 凸包+多边形重心 模板题

hdu-4810 Wall Painting 2013ACM/ICPC亚洲区南京站现场赛

hdu-4810 Wall Painting(组合数学)

HDU - 4810 Wall Painting 二进制+组合数学+异或

HDU 4810 Wall Painting (位操作-异或)

UVA 253 Cube painting