退火近乎全wa
查看原帖
退火近乎全wa
668765
atom_yan楼主2023/10/4 22:08
#include<bits/stdc++.h>
#define int long long
using namespace std;
double T=3000,Down=0.998,eps=1e-10;
int g[8][25],ng[8][25],ans,ori[200];
int n,m;
double f(){
	double res=0,a=0;
	int y[25];
	for(int i=1;i<=m;i++) y[i]=0;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++)
			y[i]+=ng[i][j];
		a+=y[i];
	}
	a=a/(m*1.0);
	for(int i=1;i<=m;i++)
		res+=(a-y[i])*(a-y[i]);
	res=res/(m*1.0);
	return sqrt(res);
}
double gf(){
	double res=0,a=0;
	int y[25];
	for(int i=1;i<=m;i++) y[i]=0;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++)
			y[i]+=g[i][j];
		a+=y[i];
	}
	a=a/(m*1.0);
	for(int i=1;i<=m;i++)
		res+=(a-y[i])*(a-y[i]);
	res=res/(m*1.0);
	return sqrt(res);
}
int random(int x){
    return rand()*rand()%x+1;
}
double F;
void SA(){
	T=3000;
    F=gf();
    while(T>eps){
    	int g1=random(m),g2=random(m),x1=random(n),x2=random(n);
		while(g1==g2||(ng[g1][x1]==0&&ng[g2][x1]==0)) g1=random(m),g2=random(m),x1=random(n),x2=random(n);
		swap(ng[g1][x1],ng[g2][x2]);
        double Fn=f();
        if(Fn<F){
			F=Fn;
			for(int i=1;i<=m;i++)
				for(int j=1;j<=n;j++) g[i][j]=ng[i][j];
		}
        else{
            double chance=exp(-(Fn-F)/T);
            if(rand()<RAND_MAX*chance){
				F=Fn;
				for(int i=1;i<=m;i++)
					for(int j=1;j<=n;j++) g[i][j]=ng[i][j];
			}
			else{
				swap(ng[g1][x1],ng[g2][x2]);
			}
        }
        T*=Down;
    }
}
int cnt;
signed main(){
	srand(time(NULL));
	cin>>n>>m;
	cnt=n;
	for(int i=1;i<=n;i++)
		cin>>ori[i];
	for(int i=2;i<=m;i++)
		for(int j=1;j<=n;j++)
			ori[++cnt]=0;
	clock_t Begin=clock(),End;
	double ans=1e18;
	for(int k=1;k<=1;k++){
		random_shuffle(ori+1,ori+1+n*m);
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++) g[i][j]=ng[i][j]=ori[(i-1)*n+j];
		SA();
		ans=min(ans,F);
		End=clock();
		if((double)(End-Begin)/CLOCKS_PER_SEC*1000.0>=950) break;
	}
	printf("%.2f\n",ans);
	return 0;
}

求函数值就是直接O(nm)暴力求的

assert检查好像跑出来好多0.00

和题解对拍跑出来差不多甚至更优(

2023/10/4 22:08
加载中...