模拟退火求助
查看原帖
模拟退火求助
600442
DreamSoarUpward楼主2022/12/13 18:00

过不了样例。

思路类似于挡板法,在 [2,n1][2,n-1] 之间放挡板分组然后算均方差。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[105];
int vis[105];
double ans=1e18;
double t;
const double delta=0.99;
double calc(){
	int tot=1;
	int x[105]={0};
	int sum=0;
	for(int i=1;i<=n;i++){
		x[tot]+=a[i];
		if(vis[i]==1){
			tot++;
			sum+=x[i];
		}		
	}
	double hx=(double)sum/m;
	double tmp=0.0;
	for(int i=1;i<=m;i++)
		tmp+=(hx-x[i])*(hx-x[i]);
	tmp=sqrt(tmp/m);
	return tmp;
}
void sa(){
	t=2000;
	while(t>1e-15){
		memset(vis,0,sizeof(vis));
		int xx;
		for(int i=1;i<m;i++){
			do{
				xx=rand()%n+1;
			}while(xx!=1&&xx!=n&&vis[xx]!=1);
			vis[xx]=1;
		}
		double now=calc();
		double Delta=now-ans;
		if(Delta<0){
			ans=now;
		}
		else if(exp(-Delta/t)*RAND_MAX>rand()){
			ans=now;
		}
		t*=delta;
	}
}
void solve(){
	while((double)clock()/CLOCKS_PER_SEC<=0.95)
		sa();
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	solve();
	cout<<fixed<<setprecision(2)<<ans<<endl;
}
2022/12/13 18:00
加载中...