AC题解
当然,货仓选址的经典做法是排序,从数组中选择中位数
,以这个数为货仓求解即可。
那么,模拟退火能不能搜出来解呢?
下面是代码:
货仓选址– 模拟退火
#include<bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int N = 1E5 +10 ;
int n ;
int q[N] ;
double ans = 1e8 ;
double rand(double l , double r)
{
return (double) rand() / RAND_MAX * (r-l) + l ;
}
double calc(double x)
{
double res = 0 ;
for(int i = 0 ; i < n ; i ++ )
{
res += fabs(q[i] - x) ;
}
ans = min(ans , res) ;
ans = res ;
return res ;
}
void simulate_anneal()
{
int x = rand(0,40000) ;
for(double t = 40000 ; t > 1e-4 ; t *= 0.9)
{
int np = rand(x - t ,x + t ) ;
int dx = calc(np) - calc(x) ;
if(exp(-dx / t ) > rand(0,1) ) x = np ;
}
}
int main()
{
int start = clock() ;
srand(time(NULL)) ;
cin >> n ;
for(int i = 0 ; i < n ; i ++ )
{
scanf("%d" , &q[i]) ;
}
for(int i = 0 ; i < 1000 && clock() - start < 0.9 * CLOCKS_PER_SEC; i ++ )
{
simulate_anneal() ;
}
printf("%.0lf\n" , ans) ;
return 0 ;
}
然而最最欧气的时候
也仅仅是
针对此题,对模拟退火的修正:
1. 排序,使得全局函数呈现单凹
2. 将依概率迁移
修正为只有更优才迁移
3. 卡时设定为0.8s
AC 代码
#include<bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int N = 1E5 +10 ;
int n ;
int q[N] ;
double ans = 1e8 ;
double rand(double l , double r)
{
return (double) rand() / RAND_MAX * (r-l) + l ;
}
double calc(double x)
{
double res = 0 ;
for(int i = 0 ; i < n ; i ++ )
{
res += fabs(q[i] - x) ;
}
ans = min(ans , res) ;
ans = res ;
return res ;
}
void simulate_anneal()
{
int x = rand(0,40000) ;
for(double t = 40000 ; t > 1e-12 ; t *= 0.9)
{
int np = rand(x - t ,x + t ) ;
int dx = calc(np) - calc(x) ;
if(dx < 0 ) x = np ;
}
}
int main()
{
double start = clock() ;
srand(time(NULL)) ;
scanf("%d",&n) ;
for(int i = 0 ; i < n ; i ++ )
{
scanf("%d" , &q[i]) ;
}
sort(q , q+n) ;
for(int i = 0 ; i < 1000 && clock() - start < 0.8 * CLOCKS_PER_SEC; i ++ )
{
simulate_anneal() ;
}
printf("%.0lf\n" , ans) ;
return 0 ;
}
偶尔会有超时现象
玄学算法
只是玩一玩哈哈
模拟退火有算法模板么?我也想学
哈哈好呀,核心模板就是
void simulate_anneal()
,很简单的