首先是建图,把下标为0和下标为n+1的两个点设为起点和终点,把这两个点看成两个半径为0的洞,下标1~n的点为洞,则图上两点的距离为dis = |(xi,yi,zi)-(xj,yj,zj)|-ri-rj;如果dis<0,则边权为0,如果dis>0,则边权为10*dis。
有两种算法,一种是spfa+隐式图搜索,ac用时0.000,一种是直接Floyd,ac用时0.010。
spfa+隐式图
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
struct Hole{
int x, y, z, r;
Hole(int a=0, int b=0, int c=0, int d=0):x(a),y(b),z(c),r(d){}
};
Hole hole[105];
int inq[105];
double d[105];
int n;
double get_dis(int i, int j)
{
return sqrt((hole[i].x-hole[j].x)*(hole[i].x-hole[j].x)+(hole[i].y-hole[j].y)*(hole[i].y-hole[j].y)+(hole[i].z-hole[j].z)*(hole[i].z-hole[j].z))-hole[i].r-hole[j].r;
}
void spfa()
{
queue que;
memset(inq, 0, sizeof(inq));
for(int i = 0; i < n+3; i++) d[i] = inf;
d[0] = 0;
inq[0] = 1;
que.push(0);
while(!que.empty())
{
int u = que.front();
que.pop();
inq[u] = 0;
for(int i = 0; i <= n+1; i++)
{
double dis;
dis = (get_dis(u, i)<=0 ? 0:10*get_dis(u,i));
if(d[u] < inf && d[i] > d[u]+dis)
{
d[i] = d[u]+dis;
if(!inq[i])
{
que.push(i);
inq[i] = 1;
}
}
}
}
}
int main()
{
//freopen("ztest.txt","r",stdin);
int t = 1;
while(scanf("%d", &n) && n != -1)
{
int a, b, c, dd;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d%d", &a, &b, &c, &dd);
hole[i] = Hole(a, b, c, dd);
}
scanf("%d%d%d", &a, &b, &c);
hole[0] = Hole(a, b, c, 0);
scanf("%d%d%d", &a, &b, &c);
hole[n+1] = Hole(a, b, c, 0);
spfa();
double ans = d[n+1];
printf("Cheese %d: Travel time = %.0lf sec\n",t++,ans);
}
return 0;
}
Floyd
#include
#include
#include
#include
using namespace std;
const int INF = 1000000;
int n;
double d[105][105];
int x[105], y[105], z[105], r[105];
void Floyd()
{
for (int k = 1; k <= n+2;k++)
for (int i = 1; i <= n+2;i++)
for (int j = 1; j <= n+2; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
//freopen("D:\\txt.txt", "r", stdin);
int kase = 0;
while (cin>>n && n!=-1)
{
for (int i = 1; i <= n + 2;i++)
for (int j = 1; j <= n + 2;j++)
if (i == j) d[i][j] = 0;
else d[i][j] = INF;
for (int i = 1; i <= n; i++)
cin >> x[i] >> y[i] >> z[i] >> r[i];
for (int i = n + 1; i <= n + 2; i++)
{
cin >> x[i] >> y[i] >> z[i];
r[i] = 0;
}
for (int i = 1; i <= n + 2;i++)
for (int j = 1; j <= n + 2; j++)
{
if (i == j) continue;
double dis = sqrt((x[j] - x[i])*(x[j] - x[i]) + (y[j] - y[i])*(y[j] - y[i]) + (z[j] - z[i])*(z[j] - z[i]));
dis = dis - r[j] - r[i];
if (dis < 0) dis = 0;
d[i][j] = dis;
}
Floyd();
printf("Cheese %d: Travel time = %.f sec\n", ++kase, 10 * d[n+1][n+2]);
}
}