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