1. 程式人生 > >P1959 遺址_NOI導刊2009普及(6)

P1959 遺址_NOI導刊2009普及(6)

dig putc == bool class struct space 自己 alt

題意:平面上n個點(坐標$0\le x,y\le 5000,n \le 3000$)

   求以其中四個點為頂點的正方形的最大面積

$O(n^2)$枚舉兩個點作為當前正方形的對角線

那麽如何求出另外兩個點呢?

設一個點為$(ax,ay)$,另一個為$(bx,by)$

所求點$(cx,cy),(dx,dy)$

考慮正方形中點$(\frac{ax+bx}{2},\frac{ay+by}{2})$

技術分享圖片

可以求出左邊的向量為$(\frac{bx-ax}{2},\frac{by-ay}{2})$

右邊的向量等於左邊的向量旋轉(自己舉例推)$(\frac{by-ay}{2},\frac{ax-bx}{2})$

於是,右下角的點的坐標等於中點加右邊的向量

   左上角點的坐標等於中點減右邊的向量

如果那兩個點是小數,是不成立的

怎麽判斷呢?

可以發現,那兩個點的結果是由ax,ay,bx,by通過加加減減之後除以二得到的,

也就是說ax,ay,bx,by通過加加減減得到的應該是偶數

因此ax,ay,bx,by中必須要有偶數個奇數才成立!

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
using
namespace std; #define olinr return #define _ 0 #define love_nmr 0 #define DB double inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch==-) f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1
)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar(-); } if(x>9) put(x/10); putchar(x%10+0); } int n; struct node { int x; int y; }E[3050]; bool vis[5005][5005]; int ans; double eps=1e-5; inline int ok(int i,int j) { int ax=E[i].x; int ay=E[i].y; int bx=E[j].x; int by=E[j].y; if((ax^ay^bx^by)&1) return -1; //判斷是否有奇數個奇數 int cx=(ax+bx+by-ay)>>1; //四個點的坐標 int cy=(ay+by+ax-bx)>>1; int dx=(ax+bx-by+ay)>>1; int dy=(ay+by-ax+bx)>>1; if(cx<0||cy<0||dx<0||dy<0||cx>5000||cy>5000||dx>5000||dy>5000||!vis[cx][cy]||!vis[dx][dy]) return -1; //沒超範圍並且點存在 int fx=cx-ax; int fy=cy-ay; return fx*fx+fy*fy; //面積 } int main() { n=read(); for(int i=1;i<=n;i++) { E[i].x=read(); E[i].y=read(); vis[E[i].x][E[i].y]=true; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) continue; ans=max(ans,ok(i,j)); } put(ans); olinr ~~(0^_^0)+love_nmr; }

P1959 遺址_NOI導刊2009普及(6)