CodeVS1344 线型网络

时间:2023-03-09 19:56:32
CodeVS1344 线型网络
题目描述 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

正解:爬山算法。

首先这题很容易可以得到一个$O(2^{n}n^{2})$的状压$DP$的算法。然后就不会做了。。

然后这题可以写爬山算法。。我们打乱$[1,n]$的序列,然后$O(n^{2})$枚举每个$i$和$j$。

如果$dis(i-1,i)+dis(j,j+1)>dis(i-1,j)+dis(i,j+1)$,那么将$[i,j]$直接翻转一下,可以发现,这样做肯定会得到更优解。然后$rand$3000次,每次$O(n^{2})$算出最优解后取个$min$就行了。

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctime>
#define inf (1e18)
#define eps (1e-9)
#define all (1<<n)
#define N (1<<20)
#define il inline
#define RG register
#define ll long long
#define lb(x) (x & -x)
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; double f[][N],dd[][],x[],y[],ans=inf;
int dex[],n; il int gi(){
RG int x=,q=; RG char ch=getchar(); while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar(); while (ch>='' && ch<='') x=x*+ch-,ch=getchar(); return q*x;
} il double dis(RG int i,RG int j){ return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); } /*
il void work(){
cin>>n; for (RG int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]);
for (RG int s=1;s<all;++s){
for (RG int i=1;i<=n;++i){
if (!(s&(1<<(i-1)))) continue;
for (RG int j=1;j<=n;++j){
if (s&(1<<(j-1))) continue;
RG int k=s|(1<<(j-1));
if (f[j][k]<eps) f[j][k]=inf;
f[j][k]=min(f[j][k],f[i][s]+dis(i,j));
}
}
}
for (RG int i=1;i<=n;++i) if (f[i][all-1]>eps) ans=min(ans,f[i][all-1]);
printf("%0.2lf",ans); return;
}
*/ il void sv(RG int a,RG int b){
for (RG int i=a,j=b;i<=j;++i,--j) swap(dex[i],dex[j]);
return;
} il double solve(){
for (RG int i=;i<=;++i){
RG int a=rand()%n+;
RG int b=rand()%n+;
swap(dex[a],dex[b]);
}
for (RG int i=;i<n;++i)
for (RG int j=i+;j<=n;++j)
if (dd[dex[i-]][dex[i]]+dd[dex[j]][dex[j+]]>dd[dex[i-]][dex[j]]+dd[dex[i]][dex[j+]]) sv(i,j);
RG double res=; for (RG int i=;i<n;++i) res+=dd[dex[i]][dex[i+]]; return res;
} il void work(){
cin>>n; for (RG int i=;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]),dex[i]=i;
for (RG int i=;i<=n;++i)
for (RG int j=;j<=n;++j)
if (i!=j) dd[i][j]=dis(i,j);
for (RG int i=;i<=;++i){
RG double res=solve();
if (ans>res) ans=res;
}
printf("%0.2lf",ans); return;
} int main(){
File("linec");
srand(time(NULL));
work();
return ;
}