Codevs 1344 线型网络 模拟退火

本文介绍了一个关于N台PC通过最少长度的网线连接的问题,并提供了一种使用模拟退火算法解决该问题的具体实现。文章详细展示了如何通过随机选取路径并逐步优化来达到最小总线长的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1344 线型网络

时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond
题目描述 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

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
#define maxn 21
int n;
double x[maxn],y[maxn],dis[maxn][maxn];
struct Path{
    int path[maxn];
    Path(){ for(int i=0;i<n;i++) path[i]=i; }
    Path(const Path &p){
        memcpy(path,p.path,sizeof path );
        swap(path[rand()%n],path[rand()%n]);
    }
    double dist(){
        double ans=0;
        for(int i=1;i<n;i++) ans+= ::dis[path[i-1]][path[i]];
        return ans;
    }
};
bool Accept(double Delta,double temper){
    if(Delta<=0) return true;
    return rand() <= exp((-Delta)/temper) * RAND_MAX;
}
double solve(){
    const double Max_Temper = 10000;
    const double dec = 0.999;
    double temp = Max_Temper;
    Path p;
    while(temp>0.01){
        Path p2(p);
        if(Accept(p2.dist()-p.dist(),temp)) p=p2;
        temp*=dec;
    }
    return p.dist();
}
int main(){
    srand(19260817U);
    cin>>n;
    for(int i=0;i<n;i++)
        scanf("%lf%lf",&x[i],&y[i]);
    for(int i=0;i<n;i++){
        dis[i][i]=0;
        for(int j=i+1;j<n;j++)
            dis[i][j]=dis[j][i]=hypot(x[i]-x[j],y[i]-y[j]);
            //hypot 给出直角三角形的两个直角边长,返回斜边长 
    }
    double ans=1e9;
    int T = 155;
    while(T--){
        ans=min(ans,solve());
    }
    printf("%.2lf",ans);
    return 0;
}

模拟退火我不会,刚学的,不想整理了,看链接,我感觉挺不错的。
https://zhuanlan.zhihu.com/p/23968011

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值