【题目描述】
Freda的城堡——
“Freda,城堡外发现了一些入侵者!”
“喵…刚刚探究完了城堡建设的方案数,我要歇一会儿嘛lala~”
“可是入侵者已经接近城堡了呀!”
“别担心,rainbow,你看呢,这是我刚设计的导弹防御系统的说~”
“喂…别卖萌啊……”
Freda控制着N座可以发射导弹的防御塔。每座塔都有足够数量的导弹,但是每座塔每次只能发射一枚。在发射导弹时,导弹需要T1秒才能从防御塔中射出,而在发射导弹后,发射这枚导弹的防御塔需要T2分钟来冷却。
所有导弹都有相同的匀速飞行速度V,并且会沿着距离最短的路径去打击目标。计算防御塔到目标的距离Distance时,你只需要计算水平距离,而忽略导弹飞行的高度。导弹在空中飞行的时间就是 (Distance/V) 分钟,导弹到达目标后可以立即将它击毁。
现在,给出N座导弹防御塔的坐标,M个入侵者的坐标,T1、T2和V,你需要求出至少要多少分钟才能击退所有的入侵者。
【题解】
二分+dinic
我们在发射的防御塔和目标之间连一个(双向)边,跑一边看符不符合就行了。
代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int inf=30000;
const int M=1000000;
const int N=50;
double t[N*N+5][N*N+5];
double t1,t2;
int x[N+5],y[N+5];
int num,head[M+5];
bool flag[M+5];
int match[M+5];
int n,m;
double v;
struct edge
{
int u,v;
int next;
edge(){next=-1;}
}ed[M+5];
void build(int u,int v)
{
num++;
ed[num].v=v;
ed[num].next=head[u];
head[u]=num;
}
bool dfs(int u)
{
for(int i=head[u];i!=-1;i=ed[i].v)
{
int v=ed[i].v;
if(!flag[v])
{
flag[v]=1;
if(!match[v]||!dfs(match[v]))
{
match[v]=u;
return true;
}
}
}
return false;
}
bool check(double T)
{
num=0;
memset(head,-1,sizeof(head));
memset(match,0,sizeof(match));
int d=(d-T)/(t1+t2)+1;
for(int i=1;i<=n;i++)
for(int j=0;j<d;j++)
{
double now=t1+(t1+t2)*j;
for(int k=1;k<=m;k++)
{
if(now+t[i][m]<=T)
{
build(i+j*n,d*n+k);
build(d*n+k,j*n+i);
}
}
}
int ans=0;
for(int i=1;i<=d*n+m;i++)
{
memset(flag,0,sizeof(flag));
if(dfs(1))ans++;
}
return ans>>2==m;
}
double div()
{
double lf=t1,rg=inf;
for(int i=1;i<=40;i++)
{
double mid=(lf+rg)/2.0;
if(check(mid))rg=mid;
else lf=mid;
}
return rg;
}
double calc(int x1,int y1,int x2,int y2)
{
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
int main()
{
scanf("%d%d%lf%lf%lf",&n,&m,&t1,&t2,&v);
t1/=60.0;
for(int i=1;i<=m;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
for(int j=1;j<=m;j++)
t[i][j]=calc(x[j],y[j],a,b)/v;
}
printf("%.6lf\n",div());
return 0;
}