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<bits/stdc++.h>
#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<bits/stdc++.h>
#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<w.y;
	return q.x<w.x;
}
bool find(double x,double y){
	for(register int i=n;i>=(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;
}
Tags: