题意:
求三个点构成的最大三角形面积。
思路: 可以证明,三点构成的最大三角形面积一定在凸包上,传统算法for循环三次,时间复杂度为O(n^3),实际上可以把复杂度降为O(n^2)。对于给定的两点(P, Q),求得第三点R,使得PQR的三角形面积最大。
性质1:
因为凸包上满足性质:循环遍历R时,三角形面积先增后减,找到最大即可停止搜索。
性质2:
利用(P, Q)求得的点R,在搜索(Q, Q_next)的最大三角形面积时,可以从点R开始继续向后搜索,而不需要从头开始。
综上,时间复杂度降为O(n^2)。
代码如下:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;
import java.util.StringTokenizer;
public class Main{
String INPUT = "./data/judge/201710/P2079.txt";
public static void main(String[] args) throws IOException {
new Main().run();
}
class P implements Comparable<P>{
int x;
int y;
P(int x, int y){
this.x = x;
this.y = y;
}
P sub(P a) {
return new P(x - a.x, y - a.y);
}
int det(P a) {
return x * a.y - y * a.x;
}
@Override
public int compareTo(P o) {
return x - o.x != 0 ? x - o.x : y - o.y;
}
}
int N;
P[] p;
double area(P a, P b, P c) {
double ans = (c.x - a.x) * (b.y - a.y) - (c.y - a.y) * (b.x - a.x);
return 0.5 * Math.abs(ans);
}
P[] convexHull() {
Arrays.sort(p);
P[] qs = new P[2 * N];
int k = 0;
for (int i = 0; i < N; ++i) {
while (k > 1 && qs[k - 1].sub(qs[k - 2]).det(p[i].sub(qs[k - 2])) < 0) k --;
qs[k++] = p[i];
}
for (int i = N - 2, t = k; i >= 0; --i) {
while (k > t && qs[k - 1].sub(qs[k - 2]).det(p[i].sub(qs[k - 2])) < 0) k--;
qs[k++] = p[i];
}
P[] res = new P[k - 1];
System.arraycopy(qs, 0, res, 0, k - 1);
return res;
}
void solve() {
P[] qs = convexHull();
int n = qs.length;
double ans = 0;
for (int offset = 1; offset < (n + 1) / 2; ++offset) {
int fir = 0;
int pos = (fir + offset + 1) % n;
do {
int sec = (fir + offset) % n;
while ((pos + 1) % n != fir && area(qs[fir % n], qs[sec % n], qs[(pos + 1) % n])
>= area(qs[fir % n], qs[sec % n], qs[pos % n])) {
pos = (pos + 1) % n;
}
ans = Math.max(ans, area(qs[fir % n], qs[sec % n], qs[pos % n]));
fir = (fir + 1) % n;
}
while (fir != 0);
}
out.printf("%.2f\n", ans);
}
void read() {
while (true) {
N = ni();
if (N == -1) break;
p = new P[N];
for (int i = 0; i < N; ++i) {
p[i] = new P(ni(), ni());
}
solve();
}
}
FastScanner in;
PrintWriter out;
void run() throws IOException {
boolean oj;
try {
oj = ! System.getProperty("user.dir").equals("F:\\oxygen_workspace\\Algorithm");
} catch (Exception e) {
oj = System.getProperty("ONLINE_JUDGE") != null;
}
InputStream is = oj ? System.in : new FileInputStream(new File(INPUT));
in = new FastScanner(is);
out = new PrintWriter(System.out);
long s = System.currentTimeMillis();
read();
out.flush();
if (!oj){
System.out.println("[" + (System.currentTimeMillis() - s) + "ms]");
}
}
public boolean more(){
return in.hasNext();
}
public int ni(){
return in.nextInt();
}
public long nl(){
return in.nextLong();
}
public double nd(){
return in.nextDouble();
}
public String ns(){
return in.nextString();
}
public char nc(){
return in.nextChar();
}
class FastScanner {
BufferedReader br;
StringTokenizer st;
boolean hasNext;
public FastScanner(InputStream is) throws IOException {
br = new BufferedReader(new InputStreamReader(is));
hasNext = true;
}
public String nextToken() {
while (st == null || !st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch (Exception e) {
hasNext = false;
return "##";
}
}
return st.nextToken();
}
String next = null;
public boolean hasNext(){
next = nextToken();
return hasNext;
}
public int nextInt() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Integer.parseInt(more);
}
public long nextLong() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Long.parseLong(more);
}
public double nextDouble() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Double.parseDouble(more);
}
public String nextString(){
if (next == null){
hasNext();
}
String more = next;
next = null;
return more;
}
public char nextChar(){
if (next == null){
hasNext();
}
String more = next;
next = null;
return more.charAt(0);
}
}
}