题意简述
平面直角坐标系上有 个点,每个点的 坐标都在 之内, , 坐标 。每个点珂以设一个半径为 的攻击塔(攻击范围包含边界)。 轴上 的区域是敌人的进攻线,请你在每个位置都设置一些防御塔,使得敌人无法在 坐标上无限增大(敌人珂以各种绕路),并且 的最大值最小。
思路简述
抽象成图。边权为两个点之间的距离/2。设置起点S,S到一个点的距离为这个点的 坐标。设置终点T,T到一个点的距离为n-这个点的 坐标。从S到T跑最短路,路径的长度定义为路径上所有边权的最大值。
具体思路
如果我们的最大半径为 ,那么肯定每个点都要设置半径 。反正半径又不花钱,那肯定往大里放啊。
然后对于一个点 ,设距离为 。那么,两边都设置半径为 就能覆盖 之间的部分了。
当然,我们的目的是封锁 轴。稍微转化一下,就是要从左到右完美的封锁出“一条”来。“一条”珂以是曲线,看起来还很粗,只要不空出来即珂。因为敌人走位随便走,你只要一点空出来,敌人钻过去,就珂以无限向 轴延伸了。
所以,我们还要建立两个点,表示左边界和右边界。就是上面说的S和T。要说几何意义,就是S:直线x=0,T:直线x=n。然后S到一个点显然需要半径为这个点的x坐标值,才能封锁这个点到S的范围。T同理。
然后,对于我们从S到T,也就是从左到右,选择的一条链上,一个空位也不能有,也就是每个空都要完美的守住。所以这条链的长度就是最长边的值。
这样跑一遍最短路即珂。记得边权是实数,而不是整数。
代码
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define real double
#define N 1333
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
class Graph
{
public:
int head[N*N];
int EdgeCount;
struct Edge
{
int To;real Label;int Next;
}Ed[N*N<<1];
void clear(int _V=N,int _E=N<<1)
{
memset(Ed,-1,sizeof(Edge)*(_E));
memset(head,-1,sizeof(int)*(_V));
EdgeCount=-1;
}
void AddEdge(int u,int v,real w=0.0)
{
Ed[++EdgeCount]=(Edge){v,w,head[u]};
head[u]=EdgeCount;
}
void Add2(int u,int v,real w=1) {AddEdge(u,v,w);AddEdge(v,u,w);}
int Start(int u) {return head[u];}
int To(int u){return Ed[u].To;}
real Label(int u){return Ed[u].Label;}
int Next(int u){return Ed[u].Next;}
}G;
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
int n,m;
real x[N],y[N];
void Input()
{
R1(n),R1(m);
F(i,1,m) scanf("%lf%lf",&x[i],&y[i]);
}
real d(int dx,int dy){return sqrt(dx*dx+dy*dy);}//求距离
struct node{int v;real w;};bool operator<(node a,node b){return a.w>b.w;}
bool vis[N];real dis[N];
priority_queue<node> Q;
void Dijkstra(int s)
{
F(i,1,m+2) dis[i]=1e18;
Q.push((node){s,0.00});dis[s]=0.00;
while(!Q.empty())
{
node Min=Q.top();Q.pop();
int u=Min.v;
if (vis[u]) continue;
vis[u]=1;
Tra(i,u)
{int v=__v;
if (dis[v]>max(dis[u],G.Label(i)))
{
dis[v]=max(dis[u],G.Label(i));
Q.push((node){v,dis[v]});
}
}
}
}//Dijkstra算法(堆优化)
void Soviet()
{
int s=m+1,t=m+2;
G.clear();
F(i,1,m)
{
G.Add2(i,s,x[i]);
G.Add2(i,t,(n-x[i]));
}//S和T的边
F(i,1,m) F(j,1,i-1)
{
G.Add2(i,j,d(x[i]-x[j],y[i]-y[j])/2);
}//两点之间的边,边权为距离/2
Dijkstra(s);
printf("%.2f\n",dis[t]);
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}