洛谷 P2210 Haywire 题解报告

题目链接
如果不了解退火,可以先右转去这篇文章 模拟退役
注释都写在了代码里,这里不过多赘述,上代码

点击查看代码
#include<bits/stdc++.h>
#define d 0.996
#define lim 1e-10//停止温度 
#define INF 0x3f3f3f3f
using namespace std;
int n;
int ans=INF;
int del,now,nowx,nowy;
int so[18],su[18][18];
int calc()
{
	int res=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=3;j++)
			res+=abs(so[i]-so[su[i][j]]);//n<=12 直接暴力枚举,每个奶牛的位置差 
	res=res>>1;//每个奶牛的位置都算了两遍,需要除以2 
	return res;
}
void sa()
{
	double T=2021;//温度可设在1999~2021,更容易跑到最优解 
	while(T>lim)
	{
//		nowx=rand()%n+1;  
//		nowy=rand()%n+1;
//		swap(so[nowx],so[nowy]);产生两个种子,随机交换这两点的位置 
		random_shuffle(so+1,so+n+1);//此题在退火最少次数内随机打乱序列比随机交换正确率高 
		now=calc();
		del=now-ans;//温度差 
		if(del<0) ans=now;//如果温差小于0,说明此时新产生的答案now比ans更优 
		else if(exp(-del/T)<(double)rand()/RAND_MAX){//否则以一定概率接受此解(一定要写,不写会错,当板子背过就好了) 
		}
		T*=d;//降温 
	}	
} 
void work()
{
	for(int i=1;i<=12;i++) sa();//测了11次,此题可以把退火次数压缩到12(退火次数越多得到正确答案几率越大,但要注意时间复杂度 
}
int read()
{
	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<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		su[i][1]=read();//二维数组记录朋友位置 
		su[i][2]=read();
		su[i][3]=read();
		so[i]=i;//记录自己的位置 
	}
	work();
	printf("%d",ans);
	return 0;
}
上一篇:Linux下setsockopt函数相关用法


下一篇:SO单片机指南4:开发的第一步,了解目标,才能逐个击破