tyvj 1196:
因为点只有20个,用搜索就可以过,但是需要减枝一下,就是当当前计算的总距离大于已经记录的最小距离和还有大的时候,这种情况可以直接剪掉。
还有一个地方需要注意,在写的时候没注意到错了好几次。就是在搜索过程中i循环一次以后就要break,因为这题是在枚举各种组合情况,所以(a, b)(c, d)和(c, d)(a, b)其实是一样的,就不需要再重复计算。
比如说有四个点1, 2, 3, 4
程序会先搜到(1, 2)(3, 4)这种情况,如果不break的话,继续往下搜就会出现9(3, 4)(1, 2)的情况。
#include <stdio.h>
#include <string.h>
#include <math.h>
struct node
{
double x, y;
};
node p[30];
int n;
double ans, dis[30][30];
bool vis[30];
double f(node a, node b)
{
double c = a.x;
double d = a.y;
double e = b.x;
double f = b.y;
return (sqrt((c - e) * (c - e) + (d - f) * (d - f)));
}
void dfs(int c, double s)
{
int i, j;
if(c == n)
{
if(ans > s)
ans = s;
return ;
}
for(i = 0; i < n; i++)
{
if(vis[i] == 0)
{
vis[i] = 1;
for(j = i + 1; j < n; j++)
{
if(vis[j] == 0 && s + dis[i][j] < ans)
{
vis[j] = 1;
dfs(c + 2, s + dis[i][j]);
vis[j] = 0;
}
}
vis[i] = 0;
break;//注意这个break,保证在以后搜的情况之前没有搜到过,这里是组合不是排列
}
}
}
int main (void)
{
while(scanf("%d", &n) != EOF)
{
int i, j;
for(i = 0; i < n; i++)
scanf("%lf %lf", &p[i].x, &p[i].y);
ans = 0x3f3f3f3f;
memset(vis, 0, sizeof(vis));
for(i = 0; i < n; i++)
{
for(j = i + 1; j < n; j++)
{
dis[i][j] = dis[j][i] = f(p[i], p[j]);
}
}
dfs(0, 0.0);
printf("%.2lf\n", ans);
}
return 0;
}