HDU 3644

模拟退火算法。。。。

这道题,呃。我怎么感觉他就是随机的。同一个代码,时而AC,时而WA。其实还真的是随机的。呵呵呵呵呵。。。因为下降火太快了,没办法,而降得慢又会。。。TLE,虽然精度提高了。

敢问,还有什么好的方法?我是在做退火算法时遇到这个练手的。

 

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <time.h>

using namespace std;
const int MAXN=55;
const double PI=3.141592653;
const double eps=1e-5;

#define zero(a) fabs(a)<eps

struct point {
	double x,y;
};
struct Segment{
	point a,b;
};

point p[MAXN]; int n; double ans; int cot;
point tar[MAXN]; double best[MAXN]; double R;

point operator -(point &u,point &v){
	point re;
	re.x=u.x-v.x; re.y=u.y-v.y;
	return re;
}

double dot(point &u,point &v){
	return u.x*v.x+u.y*v.y;
}

double dist(point tt){
	return sqrt(tt.x*tt.x+tt.y*tt.y);
}
double multi(point &u,point &v){
	return u.x*v.y-u.y*v.x;
}
/*
bool whether_in(point &t){
	double angle=0;
	for(int i=0;i<n;i++){
		point A=p[i]-t;
		point B=p[i+1]-t;
		angle+=acos(dot(A,B)/dist(A)/dist(B));
	}
	if(fabs(angle-PI*2)<1e-5)
	return true;
	return false;
}

*/


double xmul(point p0,point p1,point p2){  
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);  
}

bool online(point p1,point p2,point p){  
    if(zero(xmul(p1,p2,p))&&((p.x-p1.x)*(p.x-p2.x)<eps&&(p.y-p1.y)*(p.y-p2.y)<eps))  
        return true;  
    return false;  
}

inline bool across(Segment s1,Segment s2){  
    if(xmul(s1.a,s1.b,s2.a)*xmul(s1.a,s1.b,s2.b)<eps)  
        if(xmul(s2.a,s2.b,s1.a)*xmul(s2.a,s2.b,s1.b)<eps)  
            return true;  
    return false;  
}

bool whether_in(point cen){  
    int cnt=0;  
    Segment s,e;  
    s.a=cen;s.b.y=cen.y;s.b.x=20000.0;  
    for(int i=0;i<n;i++){  
        e.a=p[i];e.b=p[i+1];  
        if(online(p[i],p[i+1],cen)) return false;  
        if(zero(p[i].y-p[i+1].y)) continue;  
        if(online(s.a,s.b,p[i])){  
            if(p[i].y>p[i+1].y) cnt++;  
        }  
        else if(online(s.a,s.b,p[i+1])){  
            if(p[i+1].y>p[i].y) cnt++;  
        }  
        else if(across(s,e))  
            cnt++;  
    }  
    return cnt&1;  
}


double count_d(point &tt){
	double mm=1e10; double tp;
	for(int i=0;i<n;i++){
		point A=tt-p[i];
		point B=p[i+1]-p[i];
		if(dot(A,B)<=0){ 
			 tp=dist(A);
		//	 cout<<"1"<<' '<<tp<<endl;
			 mm=min(mm,tp);
			 continue;
		}
		A=tt-p[i+1];
		B=p[i]-p[i+1];
		if(dot(A,B)<=0){
			tp=dist(A);
			mm=min(mm,tp);
		//	cout<<"2"<<' '<<tp<<endl; 
			continue;
		}
		double area=multi(A,B);
		tp=fabs(area)/dist(p[i]-p[i+1]);
	//	cout<<"3"<<' '<<tp<<endl;
		mm=min(mm,tp);
	}
	return mm;
}

double getdouble(){
	double re=((rand()*rand())%1000000)*1.0/1e6;
	return re;
}

int main(){
	srand(time(0));
	while(scanf("%d",&n),n){
		cot=0;
		for(int i=0;i<n;i++)
		scanf("%lf%lf",&p[i].x,&p[i].y);
		scanf("%lf",&R);
		p[n]=p[0];
		point tmp;
		for(int i=0;i<n;i++){
		tmp.x=(p[i].x+p[i+1].x)/2;
		tmp.y=(p[i].y+p[i+1].y)/2;
		tar[cot++]=tmp;
		}
	//	cout<<cot<<endl;
		bool flag=false;
		for(int i=0;i<cot;i++){
			best[i]=0;
		}
	//	cout<<"YES"<<endl;
		double T=50; 
		for(double t=T;t>1e-4;t*=0.55){
			for(int i=0;i<cot;i++){
				for(int j=0;j<10;j++){
					double td=getdouble();
					if(rand()&1) td*=-1;
					tmp.x=tar[i].x+td*t;
					td=getdouble();
					if(rand()&1) td*=-1;
					tmp.y=tar[i].y+td*t;
					if(whether_in(tmp)){
						td=count_d(tmp);
						if(td>best[i]){
							best[i]=td;
							tar[i]=tmp;
						}
						if(td>=R||fabs(td-R)<1e-4){
					//		cout<<tmp.x<<' '<<tmp.y<<endl;
					//		cout<<td<<endl;
							flag=true;
							break;
						}
					}
				}
				if(flag) break;
			}
			if(flag) break;
		}
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

  

posted @ 2014-08-12 16:14  chenjunjie1994  阅读(222)  评论(0编辑  收藏  举报