UVA 132 Bumpy Objects【凸包變形】【附圖】

題目大意:拋過題意,直接抽取模型。

                     平穩邊:

                     1,多邊形上兩頂點之間的邊,與多邊形非規範相交(通俗點就是線段沿着凸包的輪廓走!)。

                     2,通過旋轉多邊形使該邊水平,並且多邊形重心在其上方,重心在線段兩端點之間。

                     題目要求:多邊形頂點逆時針給出,給每條平穩線段編號(取線段頂點最大值),求出編號最小的平穩邊的編號。

解題策略:求出多邊形凸包,逆時針枚舉凸包每一條邊;

                    重心在不在其上方——>叉積計算螺旋方向判斷

                    重心在不在線段兩端點之間——>根據點積判斷,我寫了下流程判斷,大家可以參考下:


                   

           這道題又是1A,感覺最近有進步!加油!生氣

/*
   UVA 132 Bumpy Objects
   AC by J_Dark
   ON 2013/5/8  9:25
   Time 0.012s
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <climits>
#include <algorithm>
#include <vector>
using namespace std;
/////////////////////////////////////
struct point{
	double x, y;
	int iniPos;
	point(double a=0, double b=0, int c=-1){
		x = a;
		y = b;
		iniPos = c;  //記錄凸包頂點在原多邊形位置
	}
	void set(double a, double b){
		x = a;
		y = b;
	}
	double Distance(point t){
		return sqrt((x-t.x)*(x-t.x) + (y-t.y)*(y-t.y));
	}
};
vector<point> p;
vector<int> CH; //存放凸包頂點序號   模擬棧
int top, nodeNum;
point MC;  //重心
string polyName;
/////////////////////////////////////
void Input(){
	p.clear();
	CH.clear();
	double xx, yy;
    cin >> xx >> yy;
	MC.set(xx,yy);  //重心
	nodeNum = 0;
	while(cin >> xx >> yy && (xx || yy))
	{
		p.push_back(point(xx, yy, ++nodeNum));
		//nodeNum++;
	}
	CH.resize(nodeNum+5);
}

//計算凸包
bool cmp(point a, point b){
	if(a.y == b.y)  return a.x < b.x;
	return a.y < b.y;
}
bool turnRight(point px1, point px2, point pp){
    const double eps = 1e-20;
	if((px2.x - px1.x)*(pp.y - px2.y) - (pp.x - px2.x)*(px2.y - px1.y) <= eps) return true;
	return false;
}
void ComputeCH(){
	sort(p.begin(), p.end(), cmp);
	CH[0] = 0;
	CH[1] = 1;

	top = 1;
	//從起點0到到排序最後點作凸包右鏈  過程1
	for(int i=2; i<nodeNum; i++){
		while( top && turnRight(p[CH[top-1]], p[CH[top]], p[i]) )
		{
		   top--;
		}
		CH[++top] = i;
	}

	int len = top;
	//從排序最高點到到起點0fab反向作凸包右鏈  過程2
	CH[++top] = nodeNum-2;
	for(int i=nodeNum-3; i>=0; i--){
		//top!=len, 不考慮已在過程1生成凸包上的點
		while( top!=len && turnRight(p[CH[top-1]], p[CH[top]], p[i]) )
		{
		   top--;
		}
		CH[++top] = i;
	}
}
//計算p2-p1-pp三邊夾角cos大小正負
bool between(point p1, point p2, point pp){
	if( ((pp.x-p1.x)*(p2.x-p1.x)+(pp.y-p1.y)*(p2.y-p1.y)) / fabs(pp.Distance(p1)* p2.Distance(p1)) > 0)
	   return true;
	return false;
}

void findAns(){
	int ans = INT_MAX;
	//cout << "nodeNum : " << nodeNum << endl;
	for(int i=0; i<top; i++){
		//若重心在凸包當前邊左側且重心在當前邊兩端點之間
		if(!turnRight(p[CH[i]], p[CH[(i+1)%top]], MC)
		   &&  between(p[CH[i]], p[CH[(i+1)%top]], MC)
		   && between(p[CH[(i+1)%top]], p[CH[i]], MC)){
			ans = min(ans, max(p[CH[i]].iniPos, p[CH[(i+1)%top]].iniPos));
			//printf("ans = %d  %d %d\n", ans, p[CH[i]].iniPos, p[CH[(i+1)%top]].iniPos);
		}
	}
	//經驗證,一個空格足矣
	cout << polyName << " " << ans << endl;
}


///////////////////////////////////////////////////////
int main(){
	while(cin >> polyName && polyName[0]!='#')
	{
		Input();
		ComputeCH(); //計算凸包
		findAns();  //找到編號基邊最大最小值
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章