BZOJ 3680 吊打XXX(模拟退火)
一个很好玩的概率算法。
总是接受比当前解的邻域里更优的解,以一个类似于退火的概率接受邻域里次的解。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-3 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=100005; //Code begin... struct Node{double x, y, w;}now, ans, point[N]; int n; double total=1e16; inline double Dist(Node a, Node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} inline double Statistic(Node p){ double res=0; FO(i,0,n) res+=Dist(p,point[i])*point[i].w; if (res<total) total=res, ans=p; return res; } inline double Rand(){return (rand()%1000+1)/1000.0;} int main () { Node tmp; srand(10086); scanf("%d",&n); FO(i,0,n) scanf("%lf%lf%lf",&point[i].x,&point[i].y,&point[i].w), now.x+=point[i].x, now.y+=point[i].y, now.w+=point[i].w; now.x/=n; now.y/=n; now.w/=n; double T=100000.0, alpha, sub; while (T>eps) { alpha=2.0*pi*Rand(); tmp.x=now.x+T*cos(alpha); tmp.y=now.y+T*sin(alpha); sub=Statistic(now)-Statistic(tmp); if (sub>=0||exp(sub/T)>=Rand()) now=tmp; T*=0.94; } T=0.001; FOR(i,1,1000) { alpha=2.0*pi*Rand(); tmp.x=ans.x+T*cos(alpha)*Rand(); tmp.y=ans.y+T*sin(alpha)*Rand(); Statistic(tmp); } printf("%.3lf %.3lf\n",ans.x,ans.y); return 0; }