1. 程式人生 > >[JSOI2004]平衡點 / 吊打XXX

[JSOI2004]平衡點 / 吊打XXX

從自己的直觀感覺上,應該目標函式是一個單峰函式,因此不需要用到模擬退火的思想----以一定的概率接受更差解,只需爬山即可。這玩意兒太玄學了,大概是剛學,還不太理解這個過程吧。自己寫的爬山一會兒在bzoj可以過,洛谷過不了,修改了一些引數後又恰恰相反,而且還有精度低時洛谷可以過,把精度調高反而wa了,很是玄乎。

寫法一:

#include<bits/stdc++.h>
using namespace std;

int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
int n,x[10005],y[10005],w[10005];
double T=200000,T_min=1e-4,delta=0.98;
double nowx,nowy,now;
double nextx,nexty,next;

double calc(double px,double py)
{
	double pos=0;
	for(int i=0;i<n;i++)pos+=w[i]*sqrt((px-x[i])*(px-x[i])+(py-y[i])*(py-y[i]));
	return pos;
}

int main()
{
	//freopen("input.in","r",stdin);
	cin>>n;
	for(int i=0;i<n;i++)cin>>x[i]>>y[i]>>w[i];
	
	now=calc(nowx,nowy);
	while(T>T_min)
	{  
		    int i=rand()%4;
			nextx=nowx+dx[i]*T;
			nexty=nowy+dy[i]*T;
			next=calc(nextx,nexty);
			if(next<now)
			{
				now=next;
				nowx=nextx;
				nowy=nexty;
			}
		T*=delta;
	}     
	printf("%.3f %.3f\n",nowx,nowy);
	return 0;
}

寫法二:

#include<bits/stdc++.h>
using namespace std;
#define LL long long 

int n,x[10005],y[10005],w[10005];
double T=192600,T_min=1e-14,delta=0.993;
double nowx,nowy,now;
double nextx,nexty,next;

double calc(double px,double py)
{
	double pos=0;
	for(int i=0;i<n;i++)pos+=w[i]*sqrt((px-x[i])*(px-x[i])+(py-y[i])*(py-y[i]));
	return pos;
}

int main()
{
	srand(time(0));
//	freopen("input.in","r",stdin);
	cin>>n;
	for(int i=0;i<n;i++)cin>>x[i]>>y[i]>>w[i];
	
	now=calc(nowx,nowy);
	while(T>T_min)
	{  
			double nextx=nowx+(rand()*2-RAND_MAX)*T;
            double nexty=nowy+(rand()*2-RAND_MAX)*T;
			next=calc(nextx,nexty);
			if(next<now)
			{
				now=next;
				nowx=nextx;
				nowy=nexty;
			}			
		
		T*=delta;
	}     
	printf("%.3f %.3f\n",nowx,nowy);
	return 0;
}