题意:
有两条直线,n个圆,让你从一条直线走到另外一条直线,问你最少需要花费多少消耗
这里在线上、圆内、圆上走路都不会产生消耗,在其他位置上由S点走到T点消耗的体力为S和T的欧几里得距离。
解析:
写这道题我就想吐槽一下这道题恶心的卡常......
我一开始用最暴力的每一个点都遍历一遍所有的点来建边,结果T了.....
然后就开始疯狂预处理优化,结果还是T.....
最后看了别人的代码,把那些预处理去掉,直接最暴力的枚举每一对点对建边就可以了
这题好像还有用DP的,但是我搞不清楚它的原理,想一想好像有点问题
SPFA 323MS
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
typedef long long ll;
using namespace std;
const double eps=1e-9;
const int MAXN =1e3+10;
const double INF = 1e18+10;
typedef struct node
{
ll x,y;
ll r;
}node;
typedef struct point
{
int x,y;
double w;
int nxt;
}point;
node con[MAXN],con2[MAXN],in12[MAXN];
int head[MAXN];
int cnt;
int num12,num,num2;
point edge[MAXN*MAXN*10];
void addedge(int u,int v,double w)
{
edge[cnt].x=u;
edge[cnt].y=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
inline double caldis(ll a,ll b,ll c,ll x0,ll y0)
{
double ans=a*x0+b*y0+c;
ans=ans<0?-ans:ans;
return ans/sqrt(a*a+b*b);
}
inline double cirdis(ll x1,ll y1,ll r1,ll x2,ll y2,ll r2)
{
double d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
return d>r1+r2?d-(r1+r2):0;
}
inline double line2(ll a,ll b,ll c1,ll c2)
{
double ans=c1-c2>0?c1-c2:c2-c1;
return ans/sqrt(a*a+b*b);
}
inline double dis_cirline(ll x,ll y,ll r,ll a,ll b,ll c)
{
double ans=caldis(a,b,c,x,y);
return ans>r?ans-r:0;
}
double d[MAXN];
struct noww{
int x;
double d;
noww(){}
noww(int a,double b){x=a;d=b;}
bool operator < (const noww & a) const
{
if(d==a.d) return x<a.x;
else return d > a.d;
}
};
int tot;
double st;
int t;
bool vis[MAXN];
queue<int> q;
void SPFA(int src){
//memset(vis,0,sizeof(vis));
for(int i=0;i<=t;i++) d[i]=st;
d[src]=0;
q.push(src);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].y;
double tmp=d[u]+edge[i].w;
if(d[v]>tmp){
d[v]=tmp;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
}
int main()
{
int n;
ll a,b,c1,c2;
scanf("%d%lld%lld%lld%lld",&n,&a,&b,&c1,&c2);
num12=num=num2=1;
cnt=0;
node tmp;
double d1,d2;
int flag=0;
int s=0;
st=line2(a,b,c1,c2);
memset(head,-1,sizeof(head));
for(int i=0;i<n;i++)
{
scanf("%lld%lld%lld",&tmp.x,&tmp.y,&tmp.r);
con[num]=tmp;
num++;
}
if(flag)
{
printf("0.000000\n");
return 0;
}
t=num;
addedge(s,t,st);
for(int i=1;i<num;i++)
{
addedge(s,i,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c1));
addedge(i,t,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c2));
for(int j=i+1;j<num;j++)
{
if(i==j) continue;
addedge(i,j,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
addedge(j,i,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
}
}
SPFA(s);
printf("%.6lf\n",d[t]);
}
Dij 727ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const double eps=1e-9;
const int MAXN =1e3+10;
const double INF = 1e18+10;
typedef struct node
{
double x,y;
double r;
}node;
typedef struct point
{
int x,y;
double w;
int nxt;
}point;
node con[MAXN];
int head[MAXN];
int num,cnt;
point edge[MAXN*MAXN*2];
void addedge(int u,int v,double w)
{
edge[cnt].x=u;
edge[cnt].y=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
inline double caldis(double a,double b,double c,double x0,double y0)
{
double ans=a*x0+b*y0+c;
ans=ans<0?-ans:ans;
return ans/sqrt(a*a+b*b);
}
inline double cirdis(double x1,double y1,double r1,double x2,double y2,double r2)
{
double d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
if(d>r1+r2) return d-(r1+r2);
else return 0;
}
inline double line2(double a,double b,double c1,double c2)
{
double ans=c1-c2>0?c1-c2:c2-c1;
return ans/sqrt(a*a+b*b);
}
inline double dis_cirline(double x,double y,double r,double a,double b,double c)
{
double ans=caldis(a,b,c,x,y);
if(ans>r) return ans-r;
else return 0;
}
double dis[MAXN];
struct noww{
int x;
double d;
noww(){}
noww(int a,double b){x=a;d=b;}
bool operator < (const noww & a) const
{
if(d==a.d) return x<a.x;
else return d > a.d;
}
};
void Dijkstra(int s)
{
int i;
for(i=0;i<=num;i++) dis[i]=INF;
dis[s]=0;
//用优先队列优化
priority_queue<noww> q;
q.push(noww(s,dis[s]));
while(!q.empty())
{
noww x=q.top();q.pop();
for(i=head[x.x];i!=-1;i=edge[i].nxt)
{
if(dis[edge[i].y]>x.d+edge[i].w)
{
dis[edge[i].y]=x.d+edge[i].w;
q.push(noww(edge[i].y,dis[edge[i].y]));
}
}
}
}
int main()
{
int n;
double a,b,c1,c2;
scanf("%d%lf%lf%lf%lf",&n,&a,&b,&c1,&c2);
num=1;
cnt=0;
node tmp;
double d1,d2;
int flag=0;
int s=0;
double st=line2(a,b,c1,c2);
int t;
memset(head,-1,sizeof(head));
for(int i=0;i<n;i++)
{
scanf("%lf%lf%lf",&tmp.x,&tmp.y,&tmp.r);
con[num]=tmp;
num++;
}
if(flag)
{
printf("0.000000\n");
return 0;
}
t=num;
addedge(s,t,st);
for(int i=1;i<num;i++)
{
addedge(s,i,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c1));
addedge(i,t,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c2));
for(int j=i+1;j<num;j++)
{
if(i==j) continue;
addedge(i,j,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
addedge(j,i,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
}
}
Dijkstra(s);
printf("%.6lf\n",dis[t]);
}