【计算几何】一点点更新

【计算几何】一点点更新
【背景】话说Mr.一首歌根本不会计算几何此等神物啊,但是当小学妹问起自己凸包神马的东西时,自己幸好还收藏着一个模版,于是就给了人家模版看,叫人家看懂graham思想后再来交流,这才发现要开始好好学计算几何了(此等动机不纯,小朋友们千万不要学我这个坏榜样)。
1.基础
❤多边形重心的计算
求多边形重心的题目大致有这么几种:
1、质量集中在顶点上
n个顶点坐标为(xi,yi),质量为mi,则重心
  X = ∑( xi×mi ) / ∑mi
  Y = ∑( yi×mi ) / ∑mi
  特殊地,若每个点的质量相同,则
  X = ∑xi / n
  Y = ∑yi / n
2、质量分布均匀
  特殊地,质量均匀的三角形重心:
  X = ( x0 + x1 + x2 ) / 3
  Y = ( y0 + y1 + y2 ) / 3
3、质量分布不均匀
只能用函数多重积分来算,不太会
这题的做法:
将n边形分成多个三角形,分别求出重心坐标以及质量m【因为质量分布均匀,所以可以设密度为1,则面积就是质量】
因为质量都集中在重心
所以把所有求出来的重心按逆时针连接起来又是一个多边形
但是这个多边形的质量集中在顶点上
所以可以利用上面公式进行计算
例: hdu1115
hdu1115
#include <cstdio>
#include 
<cstring>
#include 
<iostream>
#include 
<cmath>
#include 
<algorithm>
using namespace std;
const int maxn = 1000100;

struct point double x,y; }pnt[maxn] , g;

double det(point sp,point ep,point op){
    
return (sp.x-op.x)*(ep.y-op.y) - (ep.x-op.x)*(sp.y-op.y);
}


void compGravity(point pnt[] , int n) {
    point tmp;
    
double sumArea , area;
    sumArea 
= 0;
    g.x 
= g.y = 0;
    
for(int i=2;i<n;i++{
        area 
= det(pnt[i-1],pnt[i],pnt[0]);
        sumArea 
+= area;
        tmp.x 
= pnt[0].x + pnt[i-1].x + pnt[i].x;
        tmp.y 
= pnt[0].y + pnt[i-1].y + pnt[i].y;
        g.x 
+= tmp.x * area;
        g.y 
+= tmp.y * area;
    }

    g.x 
/= (sumArea * 3.0);
    g.y 
/= (sumArea * 3.0);
}

int main() {
    
int T , n;
    scanf(
"%d",&T);
    
while(T--{
        scanf(
"%d",&n);
        
for(int i=0;i<n;i++) scanf("%lf%lf",&pnt[i].x,&pnt[i].y);
        compGravity(pnt , n);
        printf(
"%.2lf %.2lf\n",g.x,g.y);
    }

    
return 0;
}


❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤
2.凸包
㈠graham扫描法的一些应用
graham模版
#include<cstdio>
#include
<cstring>
#include
<iostream>
#include
<cmath>
#include
<algorithm>
using namespace std;

struct point double x,y; };
bool mult(point sp,point ep,point op){
    
return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);
}


bool operator < (const point &l,const point &r){
    
return l.y<r.y || (l.y==r.y && l.x < r.x);
}


int graham(point pnt[],int n,point res[])//pnt是图中的所有的点,res是通过判断后在凸边行边上的点,而且这些点都是按逆时针存储的,n是所有点的个数
    int i,len,k = 0,top = 1;
    sort(pnt,pnt
+n);
    
if(n == 0return 0; res[0]=pnt[0];
    
if(n == 1return 1; res[1]=pnt[1];
    
if(n == 2return 2; res[2]=pnt[2];
    
for(i=2;i<n;i++{
        
while(top && mult(pnt[i],res[top],res[top-1]))
            top
--;
        res[
++top] = pnt[i];
    }

    len 
= top; res[++top] = pnt[n-2];
    
for(i=n-3;i>=0;i--){
        
while(top!=len && mult(pnt[i],res[top],res[top-1]))
            top
--;
        res[
++top]=pnt[i];
    }

    
return top; //  返回凸包中点的个数
}


① hdu1392 求凸包周长
求得凸包后,求出相邻点的距离总和即可

point res[100001],pnt[100001];

double stlen(point a,point b){
return sqrt(pow((b.x-a.x),2) + pow((b.y-a.y),2));
}


int main(){
int n,i,k;
double len;
while(cin>>n && n){
len
= 0.0;
for(i=0;i<n;i++)
cin
>>pnt[i].x>>pnt[i].y;
if(n==1) { cout<<"0.00"<<endl;continue; }
if(n==2) { printf("%.2lf\n",stlen(pnt[0],pnt[1]));continue; }
k
= graham(pnt,n,res);
for(i=1;i<=k;i++)
len
+= stlen(res[i-1],res[i]);
printf(
"%.2lf\n",len);
}

return 0;
}


② hdu2202 求最大三角形:找到了凸包的点,同过叉积求三角形的面,最终找出最大的就OK了

point res[50001],pnt[50001];

double area(point a,point b,point c){ //利用叉积来算面积
return abs((a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x));
}


int main(){
int t,n,i,j,s;
double ar,Max;
while(cin>>n){
ar
= 0.0;
Max
= 0.0;
for(i=0;i<n;i++)
cin
>>pnt[i].x>>pnt[i].y;
int k = graham(pnt,n,res);
for(j=0;j<k-2;j++){
for(i=j+1;i<k-1;i++)
for(s=i+1;s<k;s++){
ar
=area(res[i],res[j],res[s]);
if(Max<ar) Max = ar;
}

}

printf(
"%.2lf\n",Max/2);
}

return 0;
}


③ hdu3285 
题目要把凸包边上的点输出,输出有两个规则,
1.按照y的值最大的先输出,如果一值相等就按照X值小的先输出。
2.之后要按照顺时针输出点的位置。当时自己在做的时候,用的凸包模板,凸包上的点是按逆时针保存,而却没有1条那样的规则,后来到,把逆时针倒过来就是顺时针,在去找到那个满足第一个条件的那个点在数组中位置,再从找到的位置输出就行了

point res[100001],pnt[100001],re[100001];

double stlen(point a,point b){
return sqrt(pow((b.x-a.x),2)+pow((b.y-a.y),2));
}


int main(){
int n,i,j,k,m,d,f;
cin
>>n;
while(n--){
cin
>>k>>m;
int may = -(1<<29),mix=(1<<29);
for(i=0;i<m;i++)
cin
>>pnt[i].x>>pnt[i].y;
d
= graham(pnt,m,res);
cout
<<k<<" "<<d<<endl;
for(i=d-1,j=0;i>=0;i--)
re[j
++] = res[i];
for(i=0;i<d;i++){
if(re[i].y>may){
may
=re[f=i].y;
mix
=re[i].x;
}

if(re[i].y==may && re[i].x<mix)
mix
=re[f=i].x;
}

for(i=f;i<d;i++)
cout
<<re[i].x<<" "<<re[i].y<<endl;
for(i=0;i<f;i++)
cout
<<re[i].x<<" "<<re[i].y<<endl;
}

return 0;
}


④ poj1113 
求出凸包的周长再加上一L为半径的圆的周长就是要求的

#define pi acos(-1.0)
double Dis(point p1,point p2){
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}


point p[
1000],res[1000];

int main(){
int n,len,i,s;
double dis;
while(~scanf("%d%d",&n,&len)){
for(i=0;i<n;i++)
scanf(
"%lf%lf",&p[i].x,&p[i].y);
s
= graham(p,n,res);
dis
= 0;
for(i=0;i<s-1;i++)
dis
+= Dis(res[i],res[i+1]);
dis
+= Dis(res[s-1],res[0]);
dis
+= 2 * pi * len;
printf(
"%.f\n",dis);
}

return 0;
}

今天就到这里了,谢谢各位关心:)  22:53 2012/9/8 by Mr.一首歌

你可能感兴趣的:(【计算几何】一点点更新)