题意:这题题目写得够坑的。前面一大串都是无关信息。
其实很简单,就是在二维坐标里面给出若干个圆(阴影),给出起始点和终止点。
问从起始点到终止点,怎么走可以使暴露在非阴影下的路径最短。输出最短路的值。
思路:其实很简单,刚一看,设计到圆面积感觉比较有点蒙,其实圆可以当成点来处理,如果要进去某个圆。
则朝着这个圆的圆心的直线方向走肯定是最短。所以就可以抽象成一个图。每个圆也是一个点。
点与点的路径和圆半径有关,构图时候注意一下即可。
然后dijstra算法。
#include<iostream> //#include<stdio.h> #include<math.h> //#include<memory.h> //#define min(a,b) (a<b?a:b) //#define max(a,b) (a>b?a:b) using namespace std; const int N=1005; const double inf=40000.0; double mat[N][N]; int n; struct Node { double x;double y; }s,t; struct Node2 { double x,y,r; }circle[N]; double dis[N]; bool vis[N]; void dij() { memset(vis,0,sizeof(vis)); for(int i=0;i<=n+1;i++) dis[i]=inf; dis[0]=0.0; vis[0]=true; int now=0; for(int i=1;i<=n+1;i++) { double mn=inf; int k=-1; for(int j=1;j<=n+1;j++) { if(!vis[j]) { if(mat[now][j]!=inf&&mat[now][j]+dis[now]<dis[j]) { dis[j]=mat[now][j]+dis[now]; } if(dis[j]<mn) mn=dis[j],k=j; } } now=k; vis[now]=true; if(now==n+1) { printf("%.3lf\n",dis[n+1]); break; } } } void solve() { for(int i=1;i<=n;i++) { mat[0][i]=mat[i][0]=sqrt((circle[i].x-s.x)*(circle[i].x-s.x)+(circle[i].y-s.y)*(circle[i].y-s.y))-circle[i].r; if(mat[0][i]<0.0) mat[0][i]=mat[i][0]=0.0; mat[n+1][i]=(mat[i][n+1]=sqrt((circle[i].x-t.x)*(circle[i].x-t.x) +(circle[i].y-t.y)*(circle[i].y-t.y))-circle[i].r); if(mat[n+1][i]<0.0) mat[n+1][i]=mat[i][n+1]=0.0; for(int j=i+1;j<=n;j++) { mat[i][j]=mat[j][i]=(sqrt((circle[i].x-circle[j].x)*(circle[i].x-circle[j].x)+(circle[i].y-circle[j].y)*(circle[i].y-circle[j].y))-circle[i].r-circle[j].r); if(mat[i][j]<0.0) mat[i][j]=mat[j][i]=0.0; } } mat[0][n+1]=mat[n+1][0]=sqrt((t.x-s.x)*(t.x-s.x)+(t.y-s.y)*(t.y-s.y)); dij(); } int main() { int cases; scanf("%d",&cases); while(cases--) { scanf("%d",&n); memset(circle,0,sizeof(circle)); for(int i=0;i<=n+1;i++) for(int j=0;j<=n+1;j++) mat[i][j]=inf; scanf("%lf%lf%lf%lf",&s.x,&s.y,&t.x,&t.y); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&circle[i].x,&circle[i].y,&circle[i].r); } solve(); } }