题意:给出一些电脑的二维坐标,连接两个电脑所用网线长为它们之间的直线距离再加上16 feet。要求把所有电脑连成一个串,怎样连,使得所用网线最短,并且按从一端到另一端的顺序输出连接的两个电脑间的距离。
思路:很容易想到的就是暴力枚举,将所有电脑做一个全排列,求得总长最小值的那个。这里用的递归枚举、即回溯法,进行了剪枝优化。
第一次交WA了,重读题目、看别人题解,都没找到原因。看到别人的freopen,才发现我交的里面freopen没注释掉~
Code:
#include<stdio.h>
#include<math.h>
void solve(int n,int *A,int cur,double dist);
int comp[10][2];
int A[10];//排列
double C[10];//相邻两点间距离
int bestA[10];
double bestC[10];
double bestdist;
int main()
{
//freopen("216.in","r",stdin);
//freopen("216.out","w",stdout);
int n;
int num=1;
while(scanf("%d",&n)==1 && n)
{
for(int i=0;i<n;++i)
scanf("%d%d",&comp[i][0],&comp[i][1]);
bestdist=1000000000;
double dist=0;
solve(n,A,0,dist);
printf("**********************************************************\n");
printf("Network #%d\n",num++);
for(int i=0;i<n-1;++i)
printf("Cable requirement to connect (%d,%d) to (%d,%d) is %.2lf feet.\n"
,comp[bestA[i]][0],comp[bestA[i]][1],comp[bestA[i+1]][0],comp[bestA[i+1]][1],bestC[i]);
printf("Number of feet of cable required is %.2lf.\n",bestdist);
}
return 0;
}
void solve(int n,int *A,int cur,double dist)
{
if(cur==n && dist<bestdist)
{
bestdist=dist;
for(int i=0;i<n-1;++i)
{ bestC[i]=C[i]; bestA[i]=A[i]; }
bestA[n-1]=A[n-1];
}
else
for(int i=0;i<n;++i)
{
int ok=1;
for(int j=0;j<cur;++j) if(A[j]==i) { ok=0; break; }
if(ok)
{
A[cur]=i;
if(cur)
{
int dx=comp[A[cur]][0]-comp[A[cur-1]][0];
int dy=comp[A[cur]][1]-comp[A[cur-1]][1];
double jl=16+sqrt(dx*dx+dy*dy);
C[cur-1]=jl;
dist=dist+jl;
if(jl<bestdist && dist<bestdist) solve(n,A,cur+1,dist);
dist=dist-jl;//不要忘了这里的恢复。对枚举的每个i来说,dist应该是相同的。每一次i过来时,改变了dist的值,枚举下一个i时,应该把dist恢复。
}
else solve(n,A,cur+1,dist);//不要忘了这个
}
}
}