poj1696 卷包裹法 O(N H)求凸包

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

int t,n,ans[55];
bool vis[55];

struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}a[55];
typedef Point Vector;
 
struct NODE{
	Point p,q;
};
 
int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}
 
//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
 
double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){
//	cout << A.x << "*" << B.y - A.y << "*" << B.x << endl;
	return 1.0 * (A.x*B.y - A.y*B.x);
}

double dis(Point A,Point B){
	return sqrt(1.0 * ((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)));
}

int main()
{
	scanf("%d",&t);
	while(t--){
		memset(vis,0,sizeof vis);
		scanf("%d",&n);
		int st = 0;
		double st_y = inf * 1.0,st_x = inf * 1.0;
		for(int i = 1;i <= n; i++){
			int qaq;
			scanf("%d %lf %lf",&qaq,&a[i].x,&a[i].y);
			if(a[i].y < st_y){
				st_x = a[i].x;
				st_y = a[i].y;
				st = i;
			}
		}
		vis[st] = 1;
		int cnt = 0;
		ans[++cnt] = st;
		int cur = 0,lst = 0;
		while(1){
			cur = ans[cnt];//上一个确定的点
			lst = 0;
			for(int i = 1;i <= n; i++){
				if(vis[i])continue;
				int temp = Cross(a[lst] - a[cur],a[i] - a[cur]);
		//		cout << i << ":" << temp <<endl;
				if(lst == 0 || temp < 0){//更优秀的点
					lst = i;
				}
				else if(temp == 0){
					if(dis(a[i],a[cur]) < dis(a[lst],a[cur])){//当前比上一个更近
						lst = i;
					}
				}
			}
	//		cout << lst << "#--------------\n";
			ans[++cnt] = lst;
			vis[lst] = 1;
			if(cnt == n) break;
		}
		printf("%d ",cnt);
		for(int i = 1;i <= cnt; i++) printf("%d ",ans[i]);
		printf("\n");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值