• codevs 1344 模拟退火


    1344 线型网络

     

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 钻石 Diamo
     
    题目描述 Description

    有 N ( <=20 ) 台 PC 放在机房内,现在要求由你选定一台 PC,用共 N-1 条网线从这台机器开始一台接一台地依次连接他们,最后接到哪个以及连接的顺序也是由你选定的,为了节省材料,网线都拉直。求最少需要一次性购买多长的网线。(说白了,就是找出 N 的一个排列 P1 P2 P3 ..PN 然后 P1 -> P2 -> P3 -> ... -> PN 找出 |P1P2|+|P2P3|+...+|PN-1PN| 长度的最小值)

    输入描述 Input Description

    第一行 N ,下面 N 行,每行分别为机器的坐标(x,y) ( 实数 -100<=x,y<=100 )

    输出描述 Output Description

    最小的长度,保留两位小数。

    样例输入 Sample Input

    3
    0 0
    1 1
    1 -1

    样例输出 Sample Output

    2.83

    ______________________________________________________________________________________________________________________________

    题目数据范围看似很小,实际细算,肯定超时。常规方法不行。

    随机了一下,结果能够过5个点。

    没办法了,只好模拟退火。临时学的,更确切的说是临时抄的。

    模拟退火,一种启发式搜索方法,据说是模拟物理上的退火过程而发明的。

    个人理解:

    爬山算法就是用贪心的方法求出局部最优解。就是说你只要只走上坡路就一定可以走到一个山顶,但不一定是珠穆朗玛峰。

    而模拟退火就是从一个点试着向四周蹦,如果蹦到点比这里高,那就上去(这个好理解,总忘高处走,这就是爬山算法嘛);如果蹦到的点比较低,则有定的概率上去。

    为什么一定要接受更低的点呢?只有这样才可以从局部最优的情况中跳出来,从而试着去爬更高的山。

    关键为题在于概率如何计算。也就是随着时间的推移,接受的概率要逐渐降低。

    代码如下

    1 bool accept(double delta,double cur)
    2 {
    3     if(delta<=0)return 1;    //若果跳到的点更符合要求
    4     return rand()<exp((-delta)/cur)*RAND_MAX;
    5   //若果跳到的点更差....,cur为当前温度,它会随着时间降低(退火),
    RAND_MAX为最大随机整数,exp(负数)产生0-1间的实数,明白了吗?
    6 }

    还不明白就看大神的吧!

    https://zhuanlan.zhihu.com/p/23968011

    ______________________________________________________________________________________________________________________________

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int cx[21],cxf[21];
     8 double x[21],y[21],dis[21][21];
     9 double ans;
    10 int n;
    11 double getdis(int * s)
    12 {
    13     double tp=0;
    14     for(int i=1;i<n;i++)tp+=dis[s[i-1]][s[i]];
    15     return tp;
    16 }
    17 bool accept(double delta,double cur)
    18 {
    19     if(delta<=0)return 1;
    20     return rand()<exp((-delta)/cur)*RAND_MAX;
    21 }
    22 double solve()
    23 {
    24     double dec=0.999;
    25     double tp,ttp=ans;
    26     double cur=10000;
    27     while(cur>0.01)
    28     {
    29         memcpy(cxf,cx,sizeof(cx));
    30         int a=rand()%n,b=rand()%n;
    31         swap(cxf[a],cxf[b]);
    32         tp=getdis(cxf);
    33         if(accept(tp-ttp,cur))
    34         {
    35             memcpy(cx,cxf,sizeof(cx));
    36             ttp=tp;
    37         }
    38         cur*=dec;
    39     }
    40     return ttp;
    41 }
    42 int main()
    43 {
    44     srand(2323);
    45     scanf("%d",&n);
    46     for(int i=0;i<n;++i)
    47         scanf("%lf%lf",x+i,y+i);
    48     for(int i=0;i<n;++i)
    49         for(int j=0;j<i;++j)
    50         {
    51             dis[i][j]=dis[j][i]=hypot(x[i]-x[j],y[i]-y[j]);
    52         }
    53     for(int i=0;i<n;i++)cx[i]=i;
    54     ans=getdis(cx);
    55     int t=150;
    56     while(t--)
    57     {
    58         ans=min(ans,solve());
    59     }
    60     printf("%.2lf
    ",ans);
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    类的访问级别
    包和静态引入
    数组
    流程控制
    适合初学者的ROS机器人教程(3): ROS下使用Python对UR5机器人建模与控制
    适合初学者的强化学习教程(1): python使用gym实践和注意事项
    适合初学者的ROS机器人教程(1): Ubuntu下ROS创建自己的包和使用github下载的包
    适合初学者的ROS机器人教程(2): Ubuntu下ROS使用Gazebo和Rviz对UR5机器人建模
    spyder使用IPython的ipdb调试
    mysql创建外键
  • 原文地址:https://www.cnblogs.com/gryzy/p/7009283.html
Copyright © 2020-2023  润新知