题目描述 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$就行了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #include <ctime> 15 #define inf (1e18) 16 #define eps (1e-9) 17 #define all (1<<n) 18 #define N (1<<20) 19 #define il inline 20 #define RG register 21 #define ll long long 22 #define lb(x) (x & -x) 23 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 24 25 using namespace std; 26 27 double f[21][N],dd[23][23],x[21],y[21],ans=inf; 28 int dex[23],n; 29 30 il int gi(){ 31 RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 32 if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; 33 } 34 35 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])); } 36 37 /* 38 il void work(){ 39 cin>>n; for (RG int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]); 40 for (RG int s=1;s<all;++s){ 41 for (RG int i=1;i<=n;++i){ 42 if (!(s&(1<<(i-1)))) continue; 43 for (RG int j=1;j<=n;++j){ 44 if (s&(1<<(j-1))) continue; 45 RG int k=s|(1<<(j-1)); 46 if (f[j][k]<eps) f[j][k]=inf; 47 f[j][k]=min(f[j][k],f[i][s]+dis(i,j)); 48 } 49 } 50 } 51 for (RG int i=1;i<=n;++i) if (f[i][all-1]>eps) ans=min(ans,f[i][all-1]); 52 printf("%0.2lf",ans); return; 53 } 54 */ 55 56 il void sv(RG int a,RG int b){ 57 for (RG int i=a,j=b;i<=j;++i,--j) swap(dex[i],dex[j]); 58 return; 59 } 60 61 il double solve(){ 62 for (RG int i=1;i<=100;++i){ 63 RG int a=rand()%n+1; 64 RG int b=rand()%n+1; 65 swap(dex[a],dex[b]); 66 } 67 for (RG int i=1;i<n;++i) 68 for (RG int j=i+1;j<=n;++j) 69 if (dd[dex[i-1]][dex[i]]+dd[dex[j]][dex[j+1]]>dd[dex[i-1]][dex[j]]+dd[dex[i]][dex[j+1]]) sv(i,j); 70 RG double res=0; for (RG int i=1;i<n;++i) res+=dd[dex[i]][dex[i+1]]; return res; 71 } 72 73 il void work(){ 74 cin>>n; for (RG int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]),dex[i]=i; 75 for (RG int i=1;i<=n;++i) 76 for (RG int j=1;j<=n;++j) 77 if (i!=j) dd[i][j]=dis(i,j); 78 for (RG int i=1;i<=3000;++i){ 79 RG double res=solve(); 80 if (ans>res) ans=res; 81 } 82 printf("%0.2lf",ans); return; 83 } 84 85 int main(){ 86 File("linec"); 87 srand(time(NULL)); 88 work(); 89 return 0; 90 }