1. 程式人生 > >面試OR筆試2——城堡問題1

面試OR筆試2——城堡問題1

1 題目及要求

1.1 題目描述

將軍大勝歸來,奪取許多城堡(xi,yi)。國王許可,你站在任意的城堡上,選擇任意視角,看得見的城堡都是你的,包括你站的城堡,但頭不能動。而且你不能站在城堡構成的凸焦點上。將軍的視角剛好小於180度(無限接近180度),可以看得無限遠。請計算出將軍最多能得多少城堡。如果所有的城堡都在凸焦點上(直線中的點不算凸焦點),那麼將軍一個城堡也得不到。

輸入:

第一行,整數m,表示接下來有m行。接下來的m行,每行都有2個數,表示一個城堡的座標。

輸出:

最多獲得的城堡個數。

輸入範例:

5

0 0

0 2

1 0

1 2

0.2 1.8

輸出範例:

4

1.2 測試用例

\n表示換行

15\n0 0\n0 2\n1 0\n1 2\n0.2 0.8\n答案為4

25\n0 0\n1 0\n1 1\n0 1\n0.5 0.5\n答案為3

35\n0 0\n0.5 0.5\n1 1\n1 0\n0.5 0\n答案為4

2 解答

2.1 題目分析

假設將軍站在某個城堡A上,然後朝一個方向看,為了最可能多的包含多的城堡,假設其視線的一個邊緣恰好經過某個(或者某些在一條線上的)城堡B,然後分別計算該直線兩側的點的個數n1和 n2,還得計算射線AB上的城堡個數 n0(至少為2,因為A和B在其上)。如果A是凸焦點則為0,否則為n0 + max(n1,n2)。然後將軍遍歷所有站立的城堡,返回最大的。

2.2 程式碼

#include <iostream>
#include <vector>
#include <numeric>
#include <limits>

using namespace std;

// 請完成下面這個函式,實現題目要求的功能
//當然,你也可以不按照這個模板來作答,完全按照自己的想法來 ^-^ 
struct Point {		// 定義點型別
	double x, y;
	Point(double x1 = 0, double y1 = 0) :x(x1), y(y1) {}
};
Point castleHelp(Point p1, Point p2, Point p3) {	// 輸入3點,輸出位置和夾角
	Point ret;
	p2.x -= p1.x;
	p2.y -= p1.y;
	p3.x -= p1.x;
	p3.y -= p1.y;
	ret.x = p2.x * p3.y - p3.x * p2.y;
	ret.y = acos((p2.x * p3.x + p2.y * p3.y) / sqrt((p2.x * p2.x + p2.y * p2.y) * (p3.x * p3.x + p3.y * p3.y)));
	return ret;
}

int castle(vector<Point> points) {
	int ret(0), vl(points.size());
	if (vl < 4) return 0;
	for (int k1(0); k1 < vl; ++k1)
		for (int k2(0); k2 < vl; ++k2) {
			if (k1 == k2) continue;
			int n1(0), n2(0), n0(2);
			double theta1(0), theta2(0);
			for (int k3(0); k3 < vl; ++k3) {
				if (k3 == k2 || k3 == k1) continue;
				auto p(castleHelp(points[k1], points[k2], points[k3]));
				if (p.y < 1e-9) ++n0;			// 在射線AB上
				else {
					if (p.x < 0) ++n1, theta1 = theta1 < p.y ? p.y : theta1;		// 在直線一側
					else if(0 < p.x) ++n2, theta2 = theta2 < p.y ? p.y : theta2;	// 在直線另一側
					else theta1 = acos(-1);
				}
			}
			if (acos(-1) <= theta1 + theta2) {					// 判斷是否則為凸焦點
				n1 = n1 < n2 ? n2 + n0 : n1 + n0;
				ret = ret < n1 ? n1 : ret;
			}
		}
	return ret;
}

int main() {
	int points_size(0);
	cout << "請輸入點的個數:";
	cin >> points_size;
	cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	vector<Point> points;
	Point points_item;
	cout << "請依次輸入點的座標: x y" << endl;
	for (int points_i(0); points_i < points_size; ++points_i) {
		cin >> points_item.x >> points_item.y;
		cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
		points.push_back(points_item);
	}
	cout << castle(points) << endl;
	return 0;

}