1. 程式人生 > >P1227 【[JSOI2008]完美的對稱】

P1227 【[JSOI2008]完美的對稱】

這道題,先講一下我的做題思路 這道題的最主要的目的就是算出中心,我下面稱為中點。這個中點其實很好算的,我們只需要算出最左下角的座標和最右上角的座標,然後用中點座標公式算出來就ok了,那麼這道題就做完了一半 中點座標公式: $x_{mid}=(x_{min}+x_{max})/2$ $y_{mid}=(y_{min}+y_{max})/2$ 那麼剩下的一半就是如何就算無解的情況了,首先這個中點我們已經算出來了,如果有什麼疑惑的可以自己手模一下 對於無解的情況,我們對於$(x_i,y_i)$,若此時中點為$(x_{mid},y_{mid})$,那麼這個點關於中點的中心對稱之後的點就是$(2*x_{mid}-x_i,2*y_{mid}-y_i)$ 這個時候對於這個中心對稱之後的點,我們只需要$O(n)$掃一下就可以了 那麼給出第一份程式 ``` #include #define MAXN 50000 #define INF 100000 using namespace std; double n; struct node{ double x,y; }a[MAXN]; double minx=INF,miny=INF,maxx=-INF,maxy=-INF; double sx,sy; bool find(double x,double y){ for(register int i=1;i<=n;i++){ if(a[i].x==x&&a[i].y==y) return true; //O(n) 掃一下 } return false; } bool check(){ for(register int i=1;i<=n;i++){ double x=a[i].x,y=a[i].y; if(find(2*sx-x,2*sy-y)==false) return false; //如果找不到中心對稱之後的點,說明不行 } return true; } int main(){ scanf("%lf",&n); for(register int i=1;i<=n;i++){ scanf("%lf%lf",&a[i].x,&a[i].y); minx=min(minx,a[i].x); miny=min(miny,a[i].y); maxx=max(maxx,a[i].x); maxy=max(maxy,a[i].y); } sx=(double)(maxx+minx)*1.0/2; sy=(double)(maxy+miny)*1.0/2; //算出中點 if(check()==false){ puts("This is a dangerous situation!"); }else printf("V.I.P. should stay at (%.1f,%.1f).",sx,sy); return 0; } ``` 然後就會發現這個程式跑出來慢得離譜,我的是$2.9s$,因為每一次查詢確實需要用掉太多時間,那如何去優化這個時間呢 我們可以對於所有的座標進行排序,以$x$為第一關鍵字,$y$為第二關鍵字,那麼我們的$check()$函式只需要迴圈$1$~$(n+1)/2$,然後我們的$find()$函式只需要迴圈$n$~$(n+1)/2$,這是運用了中心對稱的性質,這樣優化之後的程式是$600s+$ ``` #include #define MAXN 50000 #define INF 100000 using namespace std; int n; struct node{ double x,y; }a[MAXN]; double minx=INF,miny=INF,maxx=-INF,maxy=-INF; double sx,sy; bool cmp(node q,node w){ if(q.x==w.x) return q.y=(n-1)/2-1;i--){ //這裡的-1是因為c++是向下取整,多算一位 if(a[i].x==x&&a[i].y==y) return true; } return false; } bool check(){ for(register int i=1;i<=(n+1)/2+1;i++){ //這裡的+1和上面的理由一樣 double x=a[i].x,y=a[i].y; if(find(2*sx-x,2*sy-y)==false) return false; } return true; } int main(){ scanf("%d",&n); for(register int i=1;i<=n;i++){ scanf("%lf%lf",&a[i].x,&a[i].y); minx=min(minx,a[i].x); miny=min(miny,a[i].y); maxx=max(maxx,a[i].x); maxy=max(maxy,a[i].y); } sort(a+1,a+1+n,cmp); sx=(double)(maxx+minx)*1.0/2; sy=(double)(maxy+miny)*1.0/2; if(check()==false){ puts("This is a dangerous situation!"); }else printf("V.I.P. should stay at (%.1f,%.1f).",sx,sy); return 0