AOJ : 1226 - Fishnet

問題概要

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=1226


1*1の正方形の各辺に、n個ずつ点が打たれます。
この点を、反対側の辺に打たれた点と結び、問題文中の図のように線分を引きます。
このとき、正方形がいくつかの四角形に分断されるので、それらの四角形の中で一番大きい面積を答えるのがこの問題です。

アルゴリズム

まず、線分と線分のすべての交点の座標を求めます。
あとは、四角形の左上・右上・右下・左下になる点を二重ループで決めて面積を計算し、最大の面積を求めるだけです。
アジア地区にしては、結構簡単なレベルの幾何です。

プログラム

#include <iostream>
#include <cstdio>
#include <complex>
#include <vector>
using namespace std;

typedef complex<double> P;

#define REP(i,n,m) for(int i=n;i<m;i++)
#define rep(i,n) REP(i,0,n)

double area(vector<P> p){
  int n = p.size();
  double res = 0.0;

  rep(i,n){
    res += p[i].real() * p[(i+1)%n].imag() - p[(i+1)%n].real() * p[i].imag();
  }
  return fabs(res/2);
}

double cross(P a, P b){
  return (a.real() * b.imag() - a.imag() * b.real());
}

P intersection_l(P a1, P a2, P b1, P b2){
  P a = a2 - a1;
  P b = b2 - b1;
  return a1 + a * cross(b, b1-a1) / cross(b, a);
}

int main(void){
  int n;

  while(cin>>n && n){
    P v[n+2][n+2];

    v[0][0] = P(0,0);
    v[0][n+1] = P(1,0);
    v[n+1][0] = P(0,1);
    v[n+1][n+1] = P(1,1);

    REP(i,1,n+1) { v[0][i].imag() = 0;   cin>>v[0][i].real(); }
    REP(i,1,n+1) { v[n+1][i].imag() = 1; cin>>v[n+1][i].real(); }
    REP(i,1,n+1) { v[i][0].real() = 0;   cin>>v[i][0].imag(); }
    REP(i,1,n+1) { v[i][n+1].real() = 1; cin>>v[i][n+1].imag(); }

    REP(i,1,n+1){
      REP(j,1,n+1){
        v[i][j] = intersection_l(v[0][j],v[n+1][j],v[i][0],v[i][n+1]);
      }
    }

    double ans = 0.0;
    rep(i,n+1){
      rep(j,n+1){
        vector<P> p;
        p.push_back(v[i][j]);
        p.push_back(v[i+1][j]);
        p.push_back(v[i+1][j+1]);
        p.push_back(v[i][j+1]);
        ans = max(ans,area(p));
      }
    }
    printf("%.6lf\n",ans);
  }

  return 0;
}