SWUST power oj 2862
Description
小Y在星际旅行的过程中,意外的发现了一个神奇的圆形空间,当他的飞船进入这个空间之后,他可以在这个圆形的区域内任意飞行而不需要消耗能量。而当他的飞船不在这个圆形区域内时,消耗的能量与行驶的距离在数值上相等。在小Y的旅行途中,一共有 n个这样神奇的空间。小Y想知道,他从第s个圆上某个点出发,到达第t个圆上某个点需要的最小能量消耗。每个神奇的空间都会被表示成一个二维平面上的圆。
Input
第一行一个整数
,表示测试组数
对于每组测试样例:
第一行一个整数
,表示神奇空间的个数
第二行四个整数
,
表示起点坐标,
表示终点坐标。数据保证起点和终点均是给出的
个圆上的某一个点
接下来
行,每行三个整数
,数据保证给定的 n 个圆两两之间一定相离。
Output
对于每组样例,输出从起点到终点的最小能量消耗。
如果你的答案是 a,正确答案是 b ,只有当
时才会被认为是正确答案。
Sample Input
1
3
1 0 10 0
1 1 1
10 1 1
5 5 3
Sample Output
4.059978
思路:按输入顺序把每个圆编号为1~N,然后在输入圆的位置坐标和半径后就判断起点是哪个点,终点是哪个点,然后用链式向量星建双向有权图,然后再跑迪杰斯特拉或者spfa,floyd也可以但是我不想写了,优先队列优化迪杰斯特拉在后面。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<iostream>
#include<queue>
#include<string>
#include<math.h>
typedef long long LL;
using namespace std;
const int maxn=2e4;
const int inf=999999999;
const int mo=1000000007;
double sx,sy,tx,ty;
int cnt=0,n;
int head[maxn],vis[maxn];
double d[maxn];
struct node///链式向前星
{
int to;
double val;
int next;
}e[maxn];
struct info///存储初始点
{
double x;
double y;
double r;
}p[maxn];
void add(int start,int End,double val)///链式向前星
{
e[++cnt]={End,val,head[start]};
head[start]=cnt;
}
void init()///初始化
{
cnt=0;
memset(p,0,sizeof(p));
memset(e,0,sizeof(e));
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
d[i]=99999999999999.9;
}
double getval(double x1,double y1,double x2,double y2,double r1,double r2)///计算两个圆之间的有效距离
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))-(r1+r2);
}
bool dis(double x1,double y1,double x2,double y2,double r)///判断起点和终点
{
double ans=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
if(ans<=r)return true;
else return false;
}
void dij(int start)///迪杰斯特拉算法
{
d[start]=0;
for(int i=1;i<=n;i++){
int minpos=-1;
for(int j=1;j<=n;j++){
if((vis[j]==0)&&(minpos<0||d[j]<d[minpos]))
minpos=j;
}
vis[minpos]=1;
//if(minpos==-1)break;
for(int i=head[minpos];i!=-1;i=e[i].next){
int to=e[i].to;
double val=e[i].val;
if(d[minpos]+val<d[to])
d[to]=d[minpos]+val;
}
}
}
void spfa(int start)///spfa算法
{
queue<int>q;
q.push(start);
vis[start]=1;
d[start]=0;
while(!q.empty()){
int now=q.front();q.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=e[i].next){
int to=e[i].to;
double val=e[i].val;
if(d[now]+val<d[to]){
d[to]=d[now]+val;
if(vis[to]==0){
vis[to]=1;
q.push(to);
}
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
scanf("%lf%lf%lf%lf",&sx,&sy,&tx,&ty);
init();
double x,y,r;
int start,End;///记录起点和终点
for(int i=1;i<=n;i++){///把圆域抽象成1~n的点
scanf("%lf%lf%lf",&x,&y,&r);
p[i]=info{x,y,r};
if(dis(sx,sy,x,y,r))///判断起点
start=i;
if(dis(tx,ty,x,y,r))///判断终点
End=i;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
double val=getval(p[i].x,p[i].y,p[j].x,p[j].y,p[i].r,p[j].r);///计算两个圆之间的有效距离
add(i,j,val);///加双向边
add(j,i,val);
}
}
dij(start);
printf("%.9f\n",d[End]);
}
return 0;
}
再加一个优先队列优化迪杰斯特拉的代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<iostream>
#include<queue>
#include<string>
#include<math.h>
typedef long long LL;
using namespace std;
const int maxn=2e4;
const int inf=999999999;
const int mo=1000000007;
double sx,sy,tx,ty;
int cnt=0,n;
int head[maxn],vis[maxn];
double d[maxn];
struct dis
{
int id;
double d;
bool operator < (const dis &a)const//重载小于号
{
return d>a.d;
}
}a,b;priority_queue<dis>q;
struct node///链式向前星
{
int to;
double val;
int next;
}e[maxn];
struct info///存储初始点
{
double x;
double y;
double r;
}p[maxn];
void add(int start,int End,double val)///链式向前星
{
e[++cnt]={End,val,head[start]};
head[start]=cnt;
}
void init()///初始化
{
cnt=0;
memset(p,0,sizeof(p));
memset(e,0,sizeof(e));
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
d[i]=99999999999999.9;
while(!q.empty())q.pop();
}
double getval(double x1,double y1,double x2,double y2,double r1,double r2)///计算两个圆之间的有效距离
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))-(r1+r2);
}
bool dis(double x1,double y1,double x2,double y2,double r)///判断起点和终点
{
double ans=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
if(ans<=r)return true;
else return false;
}
void SDIJ(int start)///优先队列优化
{
a={start,0.0};
q.push(a);
d[start]=0;
while(!q.empty()){
a=q.top();q.pop();
int now=a.id;
double dnow=a.d;
vis[now]=1;
for(int i=head[now];i!=-1;i=e[i].next){
int to=e[i].to;
double val=e[i].val;
if(dnow+val<d[to]){
d[to]=dnow+val;
b={to,d[to]};
q.push(b);
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
scanf("%lf%lf%lf%lf",&sx,&sy,&tx,&ty);
init();
double x,y,r;
int start,End;///记录起点和终点
for(int i=1;i<=n;i++){///把圆域抽象成1~n的点
scanf("%lf%lf%lf",&x,&y,&r);
p[i]=info{x,y,r};
if(dis(sx,sy,x,y,r))///判断起点
start=i;
if(dis(tx,ty,x,y,r))///判断终点
End=i;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
double val=getval(p[i].x,p[i].y,p[j].x,p[j].y,p[i].r,p[j].r);///计算两个圆之间的有效距离
add(i,j,val);///加双向边
add(j,i,val);
}
}
SDIJ(start);
printf("%.9f\n",d[End]);
}
return 0;
}