2016华为机试题目:最大的凸多边形

题目描述:

给定一些点,输出最大面积的凸边形。输出起始点为x轴最左边的点,按照顺时针方向输出,每个点必须是凸边形的顶点(不输出边上或凸边形内的点)。

输入样例:  
3;1,2;2,2;3,3  
输出样例:  
1,2;3,3;2,2

注: 
- 输入数据的第一个数为点的数目,然后是分号;再后面就是以分号间隔的点; 
- 点的数目最少为3个,最多为65535; 
- 该题目和斜率相关。

个人认为,本题主要的难点在于边上的两个点倾斜角是90度的时候,这种特殊情况需要考虑,一般情况下直接根据斜率就可以找到了。

我通过从最左边的点A(如果和A垂直的有点,从最上方的点)开始,找其右边斜率最大的点,把该点加入,直到遇到最右边最下边的点B,或者到某点的时候,大于其横坐标的点不存在,那也停止查找。然后从B点往回找,找其坐标与其斜率最大的点,直到找到A或找到某一点其左边没点为止。下面是具体的程序代码

#include <iostream>
using namespace std;
int main(){
	int N;
	cin>>N;
	int **pt=new int*[N];
	for(int i=0;i<N;i++)
		pt[i]=new int[2];
	for(int i=0;i<N;i++){
		int tN1,tN2;
		cin>>tN1>>tN2;
		pt[i][0]=tN1;
		pt[i][1]=tN2;
	}
	int min=pt[0][0];
	int pmin=0;//取最左边的最上边的数
	for(int i=1;i<N;i++){
		if(pt[i][0]<min){
			min=pt[i][0];
			pmin=i;
		}else if(pt[i][0]==min){
			if(pt[i][1]>pt[pmin][1])
				pmin=i;
		}
	}
	int max=pt[0][0];
	int pmax=0;//取最右边的最下边的数
	for(int i=1;i<N;i++){
		if(pt[i][0]>max){
			max=pt[i][0];
			pmax=i;
		}else if(pt[i][0]==max){
			if(pt[i][1]<pt[pmax][1])
				pmax=i;
		}
	}
	int result[65535];//用来存放凸多边形坐标的下标
	int s=0;
	int tmpmin=pmin;
	while(tmpmin!=pmax){
		result[s++]=tmpmin;
		int temp=tmpmin;
		double tmpangle;
		for(int i=0;i<N;i++){//为了取一条斜率值给tmpangle赋初值,初值可以是最小数,也可以是任一斜率
			if(pt[i][0]>pt[tmpmin][0]){
				tmpangle=(double)((pt[i][1]-pt[tmpmin][1])/(pt[i][0]-pt[tmpmin][0])-1);
				break;
			}
		}
		for(int i=0;i<N;i++){
			if(i==tmpmin) continue;
			double ttt;
			if(pt[i][0]>pt[tmpmin][0]){
				ttt=(double)(pt[i][1]-pt[tmpmin][1])/(pt[i][0]-pt[tmpmin][0]);
				if(ttt>tmpangle){
					tmpangle=ttt;
					temp=i;
				}
			}
		}
		if(temp==tmpmin){//如果其右边没有数字,则终止循环,这是考虑最右边竖着有好几个点的情况
			tmpmin=pmax;
		}else{
			tmpmin=temp;
		}
	}
	int tmpmax=tmpmin;
	while(tmpmax!=pmin){
		result[s++]=tmpmax;
		int temp=tmpmax;
		double tmpangle;
		for(int i=0;i<N;i++){//为了取一条斜率值给tmpangle赋初值,初值可以是最小数,也可以是任一斜率
			if(pt[i][0]<pt[tmpmax][0]){
				tmpangle=(double)((pt[i][1]-pt[tmpmax][1])/(pt[i][0]-pt[tmpmax][0])-1);
				break;
			}
		}
		for(int i=0;i<N;i++){
			if(i==tmpmax) continue;
			if((pt[i][0]<pt[tmpmax][0]) && (double)(pt[i][1]-pt[tmpmax][1])/(pt[i][0]-pt[tmpmax][0])>tmpangle){
				tmpangle=(double)(pt[i][1]-pt[tmpmax][1])/(pt[i][0]-pt[tmpmax][0]);
				temp=i;
			}
		}
		if(temp==tmpmax){
			tmpmax=pmin;
		}else{
			tmpmax=temp;
		}
	}
	for(int i=0;i<s;i++){
		cout<<pt[result[i]][0]<<" "<<pt[result[i]][1]<<endl;
	}
	for(int i=0;i<N;i++)
		delete pt[i];
	delete[] pt;
	return 0;
}


如果有错误,还请高手指正。

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值