求助退火
查看原帖
求助退火
504093
dyc2022楼主2024/12/6 18:26

模拟退火,AC42+WA8 如何解决?

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 106
using namespace std;
const double eps=1e-9;
int n;
double minn=1e15;
struct Point{double x,y;}ans;
struct Seg{Point l,r;}a[N];
struct Line{double k,b;};
Point cross(Line x,Line y)
{
	double posx=(y.b-x.b)/(x.k-y.k);
	double posy=x.k*posx+x.b;
	return {posx,posy};
}
double getdis(Point x,Point y)
{
	double ret=(x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y);
	return pow(ret,0.5);
}
Point foot(Point x,Line y)
{
	Line newL={-1.0/y.k,x.y+1.0/y.k*x.x};
	return cross(newL,y);
}
double getdis(Point x,Seg y)
{
	double ans0=min(getdis(x,y.l),getdis(x,y.r));
	if(y.l.x==y.r.x)
	{
		double maxn=max(y.l.y,y.r.y),minn=min(y.l.y,y.r.y);
		if(x.y>=minn&&x.y<=maxn)ans0=min(ans0,fabs(x.x-y.l.x));
		return ans0;
	}
	double K=(y.r.y-y.l.y)/(y.r.x-y.l.x);
	double B=y.l.y-K*y.l.x;
	Line newL={K,B};
	Point ft=foot(x,newL);
	double maxn=max(y.l.x,y.r.x),minn=min(y.l.x,y.r.x);
	if(minn<=ft.x&&ft.x<=maxn)ans0=min(ans0,getdis(x,ft));
	return ans0;
}
double getans(Point x)
{
	double ans=-1e15;
	for(int i=1;i<=n;i++)ans=max(ans,getdis(x,a[i]));
	return ans;
}
void SA()
{
	double T=1e4;srand(time(0));
	while(T>1e-15)
	{
		Point tmp={ans.x+(rand()*2-RAND_MAX)*T,ans.y+(rand()*2-RAND_MAX)*T};
		double delta=getans(tmp)-minn;
		if(delta<0)ans=tmp,minn=getans(tmp);
		else if(exp(-delta/T)*RAND_MAX>rand())ans=tmp;
		T*=0.996;
	}
}
main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf%lf%lf",&a[i].l.x,&a[i].l.y,&a[i].r.x,&a[i].r.y);
		ans.x+=a[i].l.x/2.0/n+a[i].r.x/2.0/n;
		ans.y+=a[i].l.y/2.0/n+a[i].r.y/2.0/n;
	}
	minn=getans(ans);
	for(int i=1;i<=10;i++)SA();
	printf("%.20lf",minn);
	return 0;
}
2024/12/6 18:26
加载中...