解題報告-HDOJ-1086(幾何問題)

題意:

        給你幾條線段,讓你求出這些線段的所有交點數。例如輸入樣例:先輸入一個n,代表有n條線段,接着每一行輸入一天線段,每兩個數代表一個端點,0.00 0.00 1.00 1.00,代表着以0.00,0.00)和(1.00,1.00)爲兩個端點的一條線段。

思路:

        由兩個端點可以求出這條線段所在的直線方程,並由這兩個端點確定可行區間。對所有的直線兩兩聯立求得任意兩條直線之間是否有交點,並且判斷該交點是否合法(在可行區間),同時判斷該點是否曾經被記錄,若沒被記錄,交點數加1,並把這個交點記錄下來。

代碼實現:

#include <iostream>

using namespace std;

const int MAXN = 100 + 10;
typedef struct point
{
	double x,y;
}point;
point p[MAXN * MAXN];

typedef struct segment
{
	double a,b,c,d;
}segment;
segment se[MAXN];		//保存線段線段

void f(segment A, segment B, int &cnt)		//兩條線段和當前交點數
{
	double x,y;		//聯立求解x,y
	if ((A.a - A.c) / (A.b - A.d) == (B.a - B.c) / (B.b - B.d))		//A、B平行
	{
		return;
	}
	if (A.a - A.c ==0 && B.a - B.c != 0)		//A線段爲豎直線且B線段不爲豎直線
	{
		x = A.a;
		y = (B.b - B.d) * (x - B.a) / (B.a - B.c) + B.b;
	}
	else if(B.a - B.c == 0 && A.a - A.c !=0)		//B線段爲豎直線且A線段不爲豎直線
	{
		x = B.a;
		y = (A.b - A.d) * (x - A.a) / (A.a - A.c) + A.b;
	}
	else
	{
		x = (B.a * (B.b - B.d) / (B.a - B.c) - A.a * (A.b - A.d) / (A.a - A.c) + A.b - B.b) / ((B.b - B.d) / (B.a - B.c) - (A.b - A.d) / (A.a - A.c));
		y = (B.b - B.d) / (B.a - B.c) * (x - B.a) + B.b;
	}
	int flag = 1;
	if (x - A.a >= 0 && A.c - x >= 0 && x - B.a >= 0 && B.c - x >= 0)
	{
		for (int i = 0; i < cnt; i++)		//判斷是否被標記
		{
			if (p[i].x - x == 0 && p[i].y - y == 0)
			{
				flag = 0;
				break;
			}
		}
		if (flag)		//沒有被標記,保存下來
		{
			p[cnt].x = x;
			p[cnt].y = y;
			cnt++;
		}
	}
}

int main()
{
	int n;
	while (cin>>n && n)
	{
		for (int i = 0; i < n; i++)
		{
			scanf("%lf%lf%lf%lf",&se[i].a, &se[i].b, &se[i].c, &se[i].d);
			if (se[i].a > se[i].c)		//保證a<c,b<d
			{
				double m = se[i].a;
				se[i].a = se[i].c;
				se[i].c = m;

				m = se[i].b;
				se[i].b = se[i].d;
				se[i].d = m;
			}
		}

		int cnt = 0;
		for (int i = 0; i < n; i ++)
		{
			for (int j = i + 1; j < n; j++)
			{
				f(se[i], se[j], cnt);
			}
		}
		cout<<cnt<<endl;
	}
	return 0;
}


 

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