luogu链接:https://www.luogu.org/problemnew/show/P4048
bzoj链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1822
冷冻波
题目描述
WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。
当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。
在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。
现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?
输入输出格式
输入格式:
输入文件第一行包含三个整数N、M、K(N,M,K<=200),分别代表巫妖的数量、小精灵的数量和树木的数量。
接下来N行,每行包含四个整数x, y, r, t,分别代表了每个巫妖的坐标、攻击范围和施法间隔(单位为秒)。
再接下来M行,每行两个整数x, y,分别代表了每个小精灵的坐标。
再接下来K行,每行三个整数x, y, r,分别代表了每个树木的坐标。
输入数据中所有坐标范围绝对值不超过10000,半径和施法间隔不超过20000。
输出格式:
输出一行,为消灭所有小精灵的最短时间(以秒计算)。如果永远无法消灭所有的小精灵,则输出-1。
输入输出样例
输入样例#1:
2 3 1
-100 0 100 3
100 0 100 5
-100 -10
100 10
110 11
5 5 10
输出样例#1:
5
题解
用计算几何求解巫妖和精灵间能否互相到达并以此建图,然后二分时间跑二分图匹配不断更新答案即可AC。
细节
注意先判断-1的情况,二分上界取maxcd*m,即冷却时间最长的巫妖单独杀死所有精灵的情况。更新时间后重新建图,超级源点到每个巫妖的边流量取time/cd[i]+1,即总时间除以冷却时间+1(因为在time=0的时候巫妖可以发射第一发Frozen Nova),其余边流量都为1。
代码略长大家实现的时候耐心一点,其实就是计算几何+dinic没什么思维难度,主要考代码实现。
另外,洛谷上第三个点博主的裸dinic被卡T了,加个当前弧优化快了500ms,把inline去掉又快了200ms(迷。。。),bzoj无压力过。
代码
#include<bits/stdc++.h>
#define db double
#define R register
using namespace std;
const int M=50005;
const db eps=1e-8;
struct edge{int to,fl;};
struct pt{int x,y,r;};
int sig(db x){return (x>eps)-(x<-eps);}
db dis(pt a,pt b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)*1.0);}
int operator * (pt a,pt b){return a.x*b.y-a.y*b.x;}
pt operator - (pt a,pt b){return (pt){a.x-b.x,a.y-b.y};}
db dis(pt p,pt a,pt b){return abs((a-p)*(b-p)*1.0/dis(a,b));}
pt lich[M],elv[M],tree[M];
edge ed[1000005];
vector<int>x[M];
int d[M],g=0,maxcd,cd[M],s,e,n,m,k,f;
bool vis[M];
char c;
void read(int &r)
{
r=0;f=1;c=getchar();
while(!isdigit(c))
{
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c))r=(r<<1)+(r<<3)+c-'0',c=getchar();
r*=f;
}
void add(int a,int b)
{
ed[g]=(edge){b,1};
x[a].push_back(g++);
ed[g]=(edge){a,0};
x[b].push_back(g++);
}
int bfs(int s,int e)
{
R int i;
memset(d,0,sizeof(d));
queue<int>dui;
dui.push(s);
d[s]=1;
int f,hh,t;
while(!dui.empty())
{
f=dui.front();
dui.pop();
for(i=x[f].size()-1;i>=0;--i)
{
hh=x[f][i];
t=ed[hh].to;
if(d[t]||!ed[hh].fl)continue;
d[t]=d[f]+1;
dui.push(t);
}
}
return d[e];
}
int dfs(int s,int e,int minn)
{
R int i;
if(s==e||!minn)return minn;
int ans=0,hh,fl,to,tmp;
for(i=x[s].size()-1;i>=0;--i)
{
hh=x[s][i];
fl=ed[hh].fl;
to=ed[hh].to;
if(d[to]!=d[s]+1||!fl)continue;
tmp=dfs(to,e,min(minn-ans,fl));
if(!tmp)continue;
ed[hh].fl-=tmp;
ed[hh^1].fl+=tmp;
ans+=tmp;
if(minn==tmp)break;
}
return ans;
}
int dinic()
{
int ans=0;
while(bfs(e,s))
ans+=dfs(e,s,1e9);
return ans;
}
void reb(int t)
{
R int i;
int hh;
for(i=0;i<g;i+=2)
ed[i].fl=1,ed[i+1].fl=0;
for(i=x[0].size()-1;i>=0;--i)
ed[x[0][i]^1].fl=t/cd[ed[x[0][i]].to]+1;
}
void in()
{
R int i;
read(n);read(m);read(k);
e=n+m+1;
for(i=1;i<=n;++i)
read(lich[i].x),read(lich[i].y),read(lich[i].r),read(cd[i]),maxcd=max(maxcd,cd[i]);
for(i=1;i<=m;++i)
read(elv[i].x),read(elv[i].y);
for(i=1;i<=k;++i)
read(tree[i].x),read(tree[i].y),read(tree[i].r);
}
bool check(pt a,pt b)
{
R int i;
if(sig(dis(a,b)-a.r)>0) return 0;
for(i=1;i<=k;++i)
{
if(sig(dis(a,tree[i])-tree[i].r)<0)return 0;
if(sig(dis(b,tree[i])-tree[i].r)<0)return 0;
if((dis(tree[i],a,b)-tree[i].r)<0)return 0;
}
return 1;
}
void build()
{
R int i,j;
for(i=1;i<=n;++i)
add(i,0);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
if(check(lich[i],elv[j]))
{
add(j+n,i);
vis[j]=1;
}
for(i=1;i<=m;++i)
add(n+m+1,n+i);
for(i=1;i<=m;++i)
if(!vis[i])
{
printf("-1");
exit(0);
}
}
void ac()
{
int le=0,ri=m*maxcd,mid,ans,p;
while(le<=ri)
{
mid=(le+ri)>>1;
reb(mid);
p=dinic();
if(p==m)
{
ans=mid;
ri=mid-1;
}
else le=mid+1;
}
printf("%d",ans);
}
int main()
{
in();build();ac();
return 0;
}