求助模拟退火调参
查看原帖
求助模拟退火调参
285617
黑影洞人楼主2022/11/14 13:06
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#define N 1145
using namespace std;
const double eps=1e-4;
int T;
int u[N],v[N];
double x[N],y[N],st,ed;
double tim,rst,ans;
struct edge{
	int u,v;
	double w;
	bool operator<(const edge &e)const{return w<e.w;}
}a[N];
int n,m,f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
double kruskal(double mid){
	//puts("test:");
	f[0]=0;
	for(int i=1;i<=m;i++)f[i]=i,a[i]={u[i]+1,v[i]+1,x[i]*mid+y[i]};
	sort(a+1,a+m+1);
	int cnt=0;
	double res=0;
	for(int i=1;i<=m;i++){
		int u=a[i].u,v=a[i].v;
		double w=a[i].w;
	//	printf("%d %d ",u,v);
		u=find(u),v=find(v);
		if(u==v)continue;
		f[u]=v;res+=w;
		//printf("%lf %lf\n",w,res);
		if(++cnt==n-1)break;
	}
	//printf("%lf",res);
	return res;
}
void sa(){
	for(double t=max(fabs(ed),fabs(st));t>eps;t*=0.99){
		double nt=tim+t*(rand()*2-RAND_MAX);
		if(nt>ed)nt=ed;
		if(nt<st)nt=st;
		double now=kruskal(nt),del=ans-now;
		//printf("%lf %lf %lf\n",nt,now,ans);
		if(del<0)ans=now,rst=tim=nt;
		else if(exp(-del/t)*RAND_MAX<rand())tim=nt;
	}
}
void solve(){
	//kruskal(0.144);
	rst=tim=(st+ed)/2;
	ans=kruskal(tim);
	for(int i=1;i<=20;i++)sa();
	printf("%.3lf %.3lf\n",rst,ans);
}
signed main(){
	srand(time(0));
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%lf%lf",&n,&m,&st,&ed);
		for(int i=1;i<=m;i++)scanf("%d%d%lf%lf",&u[i],&v[i],&x[i],&y[i]);
		solve();
	}
	return 0;
}



2022/11/14 13:06
加载中...