問題
N個の2次元ベクトルが与えられる。このベクトルからいくつかを選び適切な順に並べ直し、凸多角形を作る。作ることのできる凸多角形のうち面積が最大のものの面積を求めよ。凸多角形が作れない場合は0を出力せよ。1≦N≦8
方針
x軸となす角度が小さい順にベクトルを並べ替える。適当に選んだベクトル集合の和がゼロベクトルなら閉じた領域を作れる。
あとは凸判定だけど、x軸となす角が小さい順に辺が並んでいるので凸になっている。(逆に凸多角形ならば、辺を反時計まわりにみれば辺とx軸がなす角はかならず増えていく。)
面積は外積を使って計算できる。
ソースコード
- using namespace std;
- #define REP(i, n) for(int i=0; i<(int)(n); i++)
- #define FOR(i, s, e) for (int i = (int)(s); i < (int)(e); i++)
- class VectorPolygon {
- template <class T> T crossProduct(T x1, T y1, T x2, T y2) {
- return x1*y2 - x2*y1;
- }
- double getArea(vector<int> &x, vector<int> &y) {
- int N = x.size();
- long long ret = 0;
- REP(i, N) {
- int j = (i+1)%N;
- ret += crossProduct<long long>(x[i], y[i], x[j], y[j]);
- }
- return 0.5*ret;
- }
- double getAngle(int x, int y) {
- double ret = atan2(y, x);
- if (ret >= 0)
- return ret;
- else
- return 2*M_PI+ret;
- }
- public:
- double maxArea(vector<int> dx, vector<int> dy) {
- int N = dx.size();
- REP(i, N) FOR(j, i+1, N) {
- if (getAngle(dx[i], dy[i]) > getAngle(dx[j], dy[j])) {
- swap(dx[i], dx[j]);
- swap(dy[i], dy[j]);
- }
- }
- REP(i, N)
- cout << dx[i] << " " << dy[i] << " " << getAngle(dx[i], dy[i]) << endl;
- double ret = 0.0;
- vector<int> vx;
- vector<int> vy;
- REP(mask, 1<<N) {
- vx.clear();
- vy.clear();
- int x = 0;
- int y = 0;
- int z = 0;
- vx.push_back(0);
- vy.push_back(0);
- REP(i, N) if (mask & 1<<i) {
- x += dx[i];
- y += dy[i];
- if (!x && !y)
- ++z;
- else {
- vx.push_back(x);
- vy.push_back(y);
- }
- }
- if (x || y || (int)vx.size() < 3) continue;
- if (z != 1) continue;
- ret = max(ret, getArea(vx, vy));
- }
- return ret;
- }
- };
0 件のコメント:
コメントを投稿