一看到这个题的时候我惊了,原来这不是我当年NOIP的那个题么,仔细一看这个题ACM/ICPC Finas2001 是个老题,心中恍然大悟原来NOIP的题也是有出处的呀,翻了一下NOIP2017,发现还是略微有些不同的,但是要是NOIP之前做过这道题,那绝对是相当的有感jio。。。。。
题目分析:
把每个点都看作洞,起点终点看做半径为0的洞,洞和洞之间的距离等于欧几里得距离减去两个洞的半径,然而这个题为什么卡了我这么长时间呢(简直气的我口吐芬芳) memset初始化double类型的数组好像不行,,,,,
复习了Dijkstra
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define Maxn 101
#define LL long long
using namespace std;
struct Node{
int Num; double dis;
Node(int Num,double dis) : Num(Num),dis(dis) { }
bool operator < (const Node& a) const {
return dis > a.dis;
}
};
const double INF = 1e9;
int x[Maxn],y[Maxn],z[Maxn],r[Maxn],vis[Maxn],n;
double g[Maxn][Maxn],dis[Maxn];
inline LL Square(int a) { return a * a; }
inline double Dist(int i,int j) {
return sqrt(Square(x[i] - x[j]) + Square(y[i] - y[j]) + Square(z[i] - z[j])) - r[i] - r[j];
}
double Dijkstra(int s,int t) {
dis[s] = 0;
priority_queue<Node> q;
while(!q.empty()) q.pop();
q.push(Node(s,0)); vis[s] = 1;
while(!q.empty()) {
Node top = q.top(); q.pop(); vis[top.Num] = 0;
if(top.Num == t) return dis[t];
for(int i=1; i<=n; i++) {
if(dis[i] > dis[top.Num] + g[top.Num][i]) {
dis[i] = dis[top.Num] + g[top.Num][i];
if(!vis[i]) q.push(Node(i,dis[i])),vis[i] = 1;
}
}
}
return -1;
}
int main(int argc,char* argv[]) {
int kase = 0,holes;
while(scanf("%d",&holes) == 1 && holes != -1) {
for(int i=1; i<=holes+2; i++) dis[i] = INF;
for(int i=1; i<=holes+2; i++)
for(int j=1; j<=holes+2; j++)
g[i][j] = INF;
memset(vis,0,sizeof(vis));
for(int i=2; i<=holes+1; i++) scanf("%d %d %d %d",&x[i],&y[i],&z[i],&r[i]);
scanf("%d %d %d",&x[1],&y[1],&z[1]); r[1] = 0; n = holes + 2;
scanf("%d %d %d",&x[n],&y[n],&z[n]); r[n] = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
g[i][j] = max(0.0,Dist(i,j));
g[j][i] = g[i][j];
//printf("%d %d %.2lf\n",i,j,g[i][j]);
}
printf("Cheese %d: Travel time = %.0lf sec\n",++kase,Dijkstra(1,n) * 10);
//printf("%.0lf\n",);
}
return 0;
}