【codevs 1344】线型网络&模拟退火详解
来源:互联网 发布:arnavi软件下载 编辑:程序博客网 时间:2024/05/29 18:49
以下都是些玄学算法,之后慢慢搞。
引入
现在假设给定一个函数,求最大值。
穷举法:直接搜索,但是效率低下。
爬山算法:每次朝着更高的地方走,走到最高点为止。但是会出现走到极大值但走不到最大值的情况。
模拟退火算法:每次朝着更高的地方走,但是“有一定概率朝着更低的地方走”,相比较爬山算法而言,模拟退火算法的改进就是尽量跳出极大值的局限。
遗传算法:和生物学中的遗传很像,初始给定一些个体,就是初始情况,个体之间的基因交换理解为一个新的方案。随着时间的推移,那些较差的个体(较差的解)逐渐被淘汰,剩下的就是较优的个体(较优的解)。
蚁群算法:一开始所有的搜索方案都是平等的,随着搜索的进行,有些路径会更优,这时候优先搜索这些较优的路径。
下面的题就是用模拟退火算法来解决。
金属冶炼的时候金属温度越高,金属分子间运动越剧烈。同样在模拟退火中,一开始的时候温度最高,接受较差解的概率越大;随着搜索的进行,温度不断降低,接受较差解的概率越小。可以这样理解,爬山算法是直接朝着高处走,而模拟退火是一开始乱跳,跳了几次之后就不再乱跳,而是也朝着最高处走,这样就能走出极大值的局限了。
就拿本题开刀了。
首先,我们要判断这个“接受较差解的概率”到底有多大。
设当前方案和之前方案的能量变化量为dE(也就是本题中,两种方案的差)。如果dE小于等于0,说明是一个较优解,则一定接受;如果dE大于0,说明是一个较差解,所以这个概率P就能从0取到1。其中T表示当前的温度,温度越高,概率也越高。
bool accept(double delta,double tmp){ if (delta <= 0) return true; return rand() % max_rand <= exp((-delta)/tmp) * max_rand;}
下面是搜索的过程,将这个函数多运行几次,找出的最优解就是答案了。
double solve(){ int i; double dis1,dis2; double res = 100000000.0; const double max_tmp = 100000;//初始温度 const double dec = 0.999;//每次降低温度的比率 double tmp = max_tmp; fo(i,1,n) p[i] = i; calc(p,dis1); while (tmp > 0.01) { drunk(); calc(pp,dis2);//随机交换两个点,表示一种新的情况 if (accept(dis2-dis1,tmp)) {fo(i,1,n) p[i] = pp[i]; dis1 = dis2;} tmp *= dec;//降温 if (dis1 < res) res = dis1; } return res;}
下面是完整程序,一般来说:
1、T大10倍,时间复杂度也大10倍;
2、dec后面多一个9,时间复杂度大10倍;
3、初温大10倍,时间复杂度大20%左右。
#include<cmath>#include<cstdio>#include<vector>#include<queue>#include<cstring>#include<iomanip>#include<stdlib.h>#include<iostream>#include<algorithm>#define ll long long#define inf 1000000000#define mod 1000000007#define N 30#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;int n,i,j,T;int cnt;int pp[N],p[N],x[N],y[N];double dis[N][N];const int max_rand = 2333333;void drunk(){ int i,x,y; fo(i,1,n) pp[i] = p[i]; x = rand() % n + 1; y = rand() % n + 1; swap(pp[x],pp[y]);}void calc(int *p,double &s){ int i; s = 0; fo(i,1,n-1) s += dis[p[i]][p[i+1]];}bool accept(double delta,double tmp){ if (delta <= 0) return true; return rand() % max_rand <= exp((-delta)/tmp) * max_rand;}double solve(){ int i; double dis1,dis2; double res = 100000000.0; const double max_tmp = 100000; const double dec = 0.999; double tmp = max_tmp; fo(i,1,n) p[i] = i; calc(p,dis1); while (tmp > 0.01) { drunk(); calc(pp,dis2); if (accept(dis2-dis1,tmp)) {fo(i,1,n) p[i] = pp[i]; dis1 = dis2;} tmp *= dec; cnt++; if (dis1 < res) res = dis1; } return res;}int main(){ cnt = 0; srand(233333); scanf("%d",&n); fo(i,1,n) scanf("%d%d",&x[i],&y[i]); fo(i,1,n) fo(j,1,n) dis[i][j] = dis[j][i] = hypot(x[i]-x[j],y[i]-y[j]); double ans = 1000000000.0; T = 150; while (T--) ans = min(ans,solve()); printf("%.2lf\n",ans); return 0;}
- 【codevs 1344】线型网络&模拟退火详解
- Codevs 1344 线型网络 模拟退火
- 线型网络
- 线型网络
- 线型网络
- 线型网络
- WIKIOI 1344 线型网络 题解与分析
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- react+react-router+react-redux全家桶小项目开发过程分享
- OpenCv-python之进一步认识像素
- 内部类二三事2
- redis linux-集群配置流程
- 剑指Offer面试题34题:丑数(Ugly Number)(while循环里面的三个小问题)
- 【codevs 1344】线型网络&模拟退火详解
- 5、Redis从入门到放弃 之 配置文件详解
- leetcode:49. Group Anagrams
- Android Key获取方式
- 在JSP页面中使用标签判断字符串长度的问题
- 体系网络
- IntelliJ IDEA中快捷键大全
- 从CSDN个人主页进入个人博客(专栏)
- Too many active concurrent transactions