1178 Bumpy Objects问题(虽然是presentation error,没办法了)

好久没写博客了,这几天有时间,写写最近的一些心得。所谓Bumpy Objects就是求一个多边形的稳定支点的问题,下图中Object1的1,2,5,6是一组,1,7,8是一组,6,7是一组。要求使得每组中最大下标最小的一组,如Object1就选1,2,5,6这一组,Object2中选4,5,6这一组。英文详细描述如下

Consider objects such as these. They are polygons, specified by the coordinates of a centre of mass and their vertices. In the figure, centres of mass are shown as black squares. The vertices will be numbered consecutively anti-clockwise as shown.

An object can be rotated to stand stably if two vertices can be found that can be joined by a straight line that does not intersect the object, and, when this line is horizontal, the centre of mass lies above the line and strictly between its endpoints. There are typically many stable positions and each is defined by one of these lines known as its base line. A base line, and its associated stable position, is identified by the highest numbered vertex touched by that line.

Write a program that will determine the stable position that has the lowest numbered base line. Thus for the above objects, the desired base lines would be 6 for object 1, 6 for object 2 and 2 for the square. You may assume that the objects are possible, that is they will be represented as non self-intersecting polygons, although they may well be concave.

其实求解思路倒也不复杂,就是先找到所有顶点的凸包(convex hull),然后找到这些凸包点中每条相邻点连成的直线,同时找到直线在多边形中的端点,如Object1中1,2,5,6这条直线,端点就是1,6。如果重心和这两个点的连线和直线都是锐角的话,那么这条直线就是稳定的,就可以找到题目要求的所谓最小点了。我的代码自己测试是没问题的,但怎么都Presentation Error,无语。找凸包用的是Graham's Scan方法。

#include <iostream>
#include <stack>
#include <vector>
#include <math.h>
#include <iomanip>
using namespace std;

typedef struct point
{
	double x;
	double y;
	int index;//记录点的index
}point;
int cal_max(int index, vector<int>* myv, vector<point>* vertices, point mass);
int find_stable(stack<int>* mys, vector<point>* vertices, point mass);
void find_first(vector<point>* vertices);
void sort(vector<point>* vertices);
bool is_left(int index, stack<int>* mys, vector<point>* vertices);
void find_convex_hull(vector<point>* vertices, stack<int>* mys);

int main()
{
	char name[20];
	vector<point> vertices;
	stack<int> mys;
	point mass;

	while(cin>>name)
	{
		vertices.clear();
		while(mys.size() > 0)
			mys.pop();
		if(strcmp(name,"#") == 0)
		{
			return 0;
		}
		cin>>mass.x>>mass.y;

		point tmp;int index = 0;
		while(cin>>tmp.x>>tmp.y)
		{
			if(tmp.x == 0 && tmp.y == 0)
			{
				break;
			}
			tmp.index = ++index;
			vertices.push_back(tmp);
		}
		find_convex_hull(&vertices, &mys);//寻找凸包
		int min = find_stable(&mys,&vertices,mass);
		cout<<setw(20)<<setiosflags(ios::left)<<name<<setw(1)<<min<<endl;
		//cout << name << ' ' << min << endl;
	}
}
//寻找凸包的Graham's Scan法
//vertices:点集, mys:凸包的stack
void find_convex_hull(vector<point>* vertices, stack<int>* mys)
{
	find_first(vertices);//找到y坐标最小的点,放在第一位
		sort(vertices);//根据和y0角度坐标排序
		mys->push(0);mys->push(1);mys->push(2);
		for(int i = 3; i < vertices->size(); i++)
		{
			int pos = mys->top();
			while(!is_left(i,mys,vertices))
			{
				mys->pop();
			}
			mys->push(i);
		}
}
//计算myv中index和index+1组成的直线的最大baseline
//myv:凸包中的点集; vertices:点集; mass:重心坐标
//返回最大的baseline
int cal_max(int index, vector<int>* myv, vector<point>* vertices, point mass)
{
	int start = index, end = index+1;
	if(end == myv->size())
		end = 0;
	start = myv->at(start);end = myv->at(end);
	point left, right;
	int max_index = 0, min_x = 65535, max_x = -65535;
	for(int i = 0; i < myv->size(); i++)
	{
		int ano = myv->at(i);
		double rate1 = (vertices->at(end).y - vertices->at(start).y)/(vertices->at(end).x - vertices->at(start).x);
		double rate2 = (vertices->at(ano).y - vertices->at(start).y)/(vertices->at(ano).x - vertices->at(start).x);
		if(vertices->at(ano).x == vertices->at(start).x)
			rate2 = (vertices->at(ano).y - vertices->at(end).y)/(vertices->at(ano).x - vertices->at(end).x);
		if(vertices->at(ano).x == vertices->at(start).x && vertices->at(end).x == vertices->at(start).x)
			rate2 = rate1 = 1;
		if(rate1 == rate2)
		{
			if(vertices->at(ano).index > max_index)
				max_index = vertices->at(ano).index;
			if(vertices->at(ano).x > max_x)
			{
				max_x = vertices->at(ano).x;
				right = vertices->at(ano);
			}
			if(vertices->at(ano).x < min_x)
			{
				min_x = vertices->at(ano).x;
				left = vertices->at(ano);
			}
		}
	}
	//判断重心是否在范围内
	point vec1, vec2;
	vec1.x = mass.x - left.x; vec1.y = mass.y - left.y;
	vec2.x = right.x - left.x; vec2.y = right.y - left.y;
	if((vec1.x*vec2.x + vec1.y*vec2.y) < 0)
		return -1;
	vec1.x = mass.x - right.x; vec1.y = mass.y - right.y;
	vec2.x = left.x - right.x; vec2.y = left.y - right.y;
	if((vec1.x*vec2.x + vec1.y*vec2.y) < 0)
		return -1;
	return max_index;
}

//找到稳定的最小baseline
//mys:凸包中的点集;vertices:点集; mass:重心坐标
//返回最小的baseline
int find_stable(stack<int>* mys, vector<point>* vertices, point mass)
{
	vector<int> myv;
	while(mys->size() > 0)
	{
		myv.push_back(mys->top());
		mys->pop();
	}
	int min_index = 65535;
	for(int i = 0; i < myv.size(); i++)
	{
		//确定直线公式
		
		int this_min = cal_max(i,&myv,vertices,mass);
		if(this_min >=0 && this_min < min_index)
		{
			min_index = this_min;
		}
	}
	if(min_index == 65536)
		return 0;
	return min_index;
}

//判断向量方向是否向左
//index:将要判断的点的位置; mys:凸包中的点集; vertices:点集
//true: 满足要求; false:不满足,朝右
bool is_left(int index, stack<int>* mys, vector<point>* vertices)
{
	int first = mys->top();mys->pop();
	int second = mys->top();mys->push(first);

	point vec1,vec2;
	point vec0;vec0.x = 0;
	vec1.y = vertices->at(first).y - vertices->at(second).y;
	vec1.x = vertices->at(first).x - vertices->at(second).x;
	vec2.y = vertices->at(index).y;
	vec2.x = vertices->at(index).x;
	vec0.y = vertices->at(first).y - vertices->at(first).x*vec1.y/vec1.x;

	if(vec1.x > 0)
	{
		if(vec2.y >= vec2.x*vec1.y/vec1.x + vec0.y)
			return true;
	}
	else if(vec1.x < 0)
	{
		if(vec2.y <= vec2.x*vec1.y/vec1.x + vec0.y)
			return true;
	}
	else
	{
		if(vec1.y * (vec2.x - vertices->at(first).x) <= 0)
			return true;
	}
	return false;
}

//找到最小y坐标的点,放在0位置
//vertices:点集
void find_first(vector<point>* vertices)
{
	for(int i = 0; i < vertices->size(); i++)
	{
		if(vertices->at(i).y < vertices->at(0).y)
			swap(vertices->at(i), vertices->at(0));
	}
}
//根据和0位置点的级角排序除第一个以外的所有点(偷懒用的插入排序...)
//vertices:点集
void sort(vector<point>* vertices)
{
	for(int i = 1; i < vertices->size(); i++)
	{
		for(int j = i; j > 1; j--)
		{
			//使用向量余弦定理做,明天
			point vec0,vec1,vec2;
			vec0.x = 1;vec0.y = 0;
			vec1.y = vertices->at(j).y - vertices->at(0).y;
			vec1.x = vertices->at(j).x - vertices->at(0).x;
			vec2.y = vertices->at(j-1).y - vertices->at(0).y;
			vec2.x = vertices->at(j-1).x - vertices->at(0).x;
			double cos1 = (vec1.x*vec0.x + vec1.y*vec0.y) / sqrt((vec1.x*vec1.x + vec1.y*vec1.y)*(vec0.x*vec0.x + vec0.y*vec0.y));
			double cos2 = (vec2.x*vec0.x + vec2.y*vec0.y) / sqrt((vec2.x*vec2.x + vec2.y*vec2.y)*(vec0.x*vec0.x + vec0.y*vec0.y));
			if(cos1 > cos2)
			{
				swap(vertices->at(j),vertices->at(j-1));
			}
			/*double rate1 = (vertices->at(j).y - vertices->at(0).y)/(vertices->at(j).x - vertices->at(0).x);
			double rate2 = (vertices->at(j-1).y - vertices->at(0).y)/(vertices->at(j-1).x - vertices->at(0).x);
			if(vertices->at(j).x - vertices->at(0).x == 0)
				rate1 = 65535;
			if(vertices->at(j-1).x - vertices->at(0).x == 0)
				rate2 = 65535;
			if(rate1*rate2 > 0 && rate1 < rate2)
			{
				swap(vertices->at(j),vertices->at(j-1));
			}
			else if(rate1*rate2 < 0 && rate1 < 0)
			{
				swap(vertices->at(j),vertices->at(j-1));
			}
			else if(rate1*rate2 == 0 && (vertices->at(j).x > vertices->at(0).x || vertices->at(j-1).x < vertices->at(0).x))
			{
				swap(vertices->at(j),vertices->at(j-1));
			}*/
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值