HDU3685 RotationalPainting 计算几何 ACM2010杭州站



题目:http://acm.hdu.edu.cn/showproblem.php?pid=3685
题意:给一个简单多边形,求有几种平放在桌面上的方法。
思路:先求重心,再求凸包,枚举凸包上的每条边,判断重心在边上的投影是否在边上,注意投影恰好在端点不算答案,累加即可

//
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<vector>
#include<map>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define CFOR(i) for(;i>0;i--)
#define DFOR(i,s,t) for(int i=(s);i>=(t);i--)
#define PFOR(i,s,t,p) for(int i=(s);i<=(t);i+=p)
#define SD(i) scanf("%d",&i)
#define SLLD(i) scanf("%lld",&i)
#define MEM(a,t) memset(a,t,sizeof(a))
#define PIA system("pause")
#define MAXINT 0xfffffff
#define MARK cout<<"MARK"<<endl;
#define BUG cout<<"error!"<<endl;
#define LL long long
using namespace std;
ifstream fin ("in.txt");
ofstream fout ("out.txt");


const double eps = 1e-8;

double sqr(double x){
	return x*x;
}

int cmp(double x){
	if( fabs(x)<eps )	return 0;
	if(x>0)	return 1;
	return -1;
}

struct point{
	double x,y;
	point(){}
	point(double a,double b)	:x(a),y(b){}
	friend point operator + (const point &a,const point &b){
		return point(a.x+b.x,a.y+b.y);
	}
	friend point operator - (const point &a,const point &b){
		return point(a.x-b.x,a.y-b.y);
	}
	friend bool operator == (const point &a,const point &b){
		return cmp(a.x-b.x)==0 && cmp(a.y-b.y)==0;
	}
	friend point operator * (const point &a,const double &b){
		return point(a.x*b,a.y*b);
	}
	friend point operator * (const double &a,const point &b){
		return point(a*b.x,a*b.y);
	}
	friend point operator / (const point &a,const double &b){
		return point(a.x/b,a.y/b);
	}
	double norm(){
		return sqrt(sqr(x)+sqr(y));
	}
	void output(){
		printf("(%.4f,%.4f)",x,y);
	}
};
double det(const point &a,const point &b){
	return a.x*b.y - a.y*b.x;
}
double dot(const point &a,const point &b){
	return a.x*b.x + a.y*b.y;
}

struct line{
	point p,v;
	line(){}
	line(point pp,point vv){p=pp;v=vv;}
	point normal(){
		return point(-v.y,v.x);
	}
};

inline point intersect(const line &la, const line &lb) {
	double t = det(lb.v, la.p - lb.p) / det(la.v, lb.v);
	return la.p + la.v * t;
}

point point_line_foot(point p,line s){
	line ln = line(p,s.normal());
	return intersect(ln,s);
}

struct polygon_convex{
	vector<point>P;
	polygon_convex(int Size=0){
		P.resize(Size);
	}
};

bool comp_less(const point &a,const point &b){
	return cmp(a.x-b.x)<0 || cmp(a.x-b.x)==0 && cmp(a.y-b.y)<0;
}

polygon_convex convex_hull(vector<point>a){
	polygon_convex res(2*a.size()+5);
	sort(a.begin(),a.end(),comp_less);
	a.erase(unique(a.begin(),a.end()),a.end());
	int m=0;
	FOR(i,0,a.size()-1){
		while(m>1&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2]))<=0)	m--;
		res.P[m++]=a[i];
	}
	int k=m;
	DFOR(i,int(a.size())-2,0){
		while(m>k&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2]))<=0)	m--;
		res.P[m++]=a[i];
	}
	res.P.resize(m);
	if(a.size()>1)	res.P.resize(m-1);
	return res;
}

struct segment{
	point a,b;
	segment(){}
	segment(point aa,point bb){a=aa;b=bb;}
};

int point_on_seg(point p,segment s){
	return cmp(dot(point(s.a-p),point(s.b-p)));
}

/****************************************************************************************************/

vector<point>a;
polygon_convex pca;
int n;

void init(){
	scanf("%d",&n);
	double vx,vy;
	a.clear();
	FOR(i,1,n){
		scanf("%lf %lf",&vx,&vy);
		a.push_back(point(vx,vy));
	}
}

void solve(){
	//ÇóÓÐÏòÃæ»ý 
	double asum=0;
	asum += det(a[0],a[a.size()-1]);
	FOR(i,0,a.size()-2){
		asum += det(a[i+1],a[i]);
	}
	asum /= 2;
	//ÇóÖØÐÄ 
	point g=point(0,0);
	FOR(i,0,a.size()-2){
		g = g+(a[i]+a[i+1])*det(a[i+1],a[i]);
	}
	g = g+(a[a.size()-1]+a[0])*det(a[0],a[a.size()-1]);
	g = g/asum/6;
	
	//͹°ü 
	pca = convex_hull(a);
	int size = pca.P.size();
	int ans=0;
	FOR(i,0,size-1){
		
		line s;
		if( i==size-1 )	s = line(pca.P[i],pca.P[0]-pca.P[i]);
		else			s = line(pca.P[i],pca.P[i+1]-pca.P[i]);
		point fot = point_line_foot(g,s);
		if( point_on_seg( fot,segment(s.p,s.p+s.v) )<0 )	ans++;
	}
	cout<<ans<<endl;
}

int main(){
//	freopen("in.txt","r",stdin);
	int T;scanf("%d",&T);
	CFOR(T){
		init();
		solve();
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值