P4048

P4048 冷冻波

给定 \(n\) 个巫妖,\(m\) 个精灵,\(k\) 棵树。
三者都可看做二维平面上的点,由坐标表示。
\(i\) 棵树的半径为 \(R_i\)
\(i\) 个巫妖每隔时间 \(t_i\) 可以杀死范围 \(r_i\) 内的一个精灵,且两者的连线不穿过任意一棵树
求杀死所有精灵最短时间,无解输出 -1。

\(n,m,k \le 300,\left\vert x_i \right\vert,\left\vert y_i \right\vert \le 10^4,r_i,R_i \le 2\times 10^4\)

首先看到最短时间,可以想到二分答案

然后判断每对巫妖和精灵之间能否攻击。
树可以抽象成圆。

  • 两点之间距离需小于巫妖攻击半径。

直接求出两点距离比较即可。

  • 两点连成的线段要和所有树相离。

求线段到每个圆心的距离,用计算几何解决。
如果距离大于半径就说明线段与圆相离。

如果存在精灵不能被任何一个巫妖攻击到就是无解。

最后是网络流部分,设当前时间为 \(x\)
源点向每个巫妖连容量为 \(\left\lfloor \dfrac{x}{t_i} \right\rfloor+1\) 的边(\(+1\) 是因为时刻 0 可以攻击)。
每个精灵向汇点连容量为 1 的边。
每个巫妖向其能攻击到的每个精灵连容量为 1 的边。
跑网络流,满流则说明能全部杀死。

时间复杂度:\(O \left(n^3+\log_2 (t_i\times n)\, \text{网络流} \right)\)

#include <bits/stdc++.h>
#define dd double
using namespace std;
const int N=2e4,INF=2e9;
struct d{dd x,y;d(dd X=0,dd Y=0){x=X;y=Y;}}w[N],j[N],s[N];
struct line{d a,b;};
dd dj(d a,d b){return a.x*b.x+a.y*b.y;}dd cj(d a,d b){return a.x*b.y-a.y*b.x;}
d operator+(d a,d b){return d(a.x+b.x,a.y+b.y);}d operator-(d a,d b){return d(a.x-b.x,a.y-b.y);}
dd len(d a,d b){return sqrt(dj(a-b,a-b));}
dd dis(line l,d p){
	if(dj(l.a-p,l.b-p)>0)
		return min(len(l.a,p),len(l.b,p));
	return abs(cj(p-l.a,l.b-l.a)/len(l.a,l.b));
}int n,m,k,st,ed,l,r=INF-1000,mid,ans=INF,mp[1001][1001];
struct E{int v,w,nt;}e[N<<1];
int fir[N],c=1,rw[N],rt[N],tim[N];int cur[N],d[N];queue <int>q;
void init(){memset(e,0,sizeof(e));memset(fir,0,sizeof(fir));c=1;}
void I(int u,int v,int w){
	e[++c]=(E){v,w,fir[u]};fir[u]=c;
	e[++c]=(E){u,0,fir[v]};fir[v]=c;
}bool bfs(){
	for(int i=0;i<=ed;i++)d[i]=0,cur[i]=fir[i];q.push(st);d[st]=1;while(!q.empty()){
		int u=q.front(),V;q.pop();for(int i=fir[u];i;i=e[i].nt)if(!d[V=e[i].v]&&e[i].w)d[V]=d[u]+1,q.push(V);
	}return d[ed];
}int dfs(int u,int fl){
	if(u==ed)return fl;int ans=0,V,re;
	for(int i=cur[u];i;i=e[i].nt){
		cur[u]=i;if(d[V=e[i].v]==d[u]+1&&e[i].w){
			re=dfs(V,min(fl,e[i].w));e[i].w-=re,e[i^1].w+=re;fl-=re,ans+=re;if(!fl)break;}
	}if(!ans)d[u]=0;return ans;
}int dinic(){int ans=0;while(bfs())ans+=dfs(st,INF);return ans;}
bool judge(int x,int y){
	if(len(w[x],j[y])>rw[x]) return 0;bool flag=1;
	for(int i=1;i<=k;i++)
		if(dis((line){w[x],j[y]},s[i])<rt[i]) flag=0;
	return flag;
}bool check(int x){
	init();
	for(int i=1;i<=n;i++)	I(st,i,x/tim[i]+1);
	for(int i=1;i<=m;i++)	I(i+n,ed,1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(mp[i][j]) I(i,j+n,1);
	return dinic()==m;
}int main(){
	freopen("test.in","r",stdin);cin>>n>>m>>k;ed=n+m+1;
	for(int i=1;i<=n;i++) cin>>w[i].x>>w[i].y>>rw[i]>>tim[i];
	for(int i=1;i<=m;i++) cin>>j[i].x>>j[i].y;
	for(int i=1;i<=k;i++) cin>>s[i].x>>s[i].y>>rt[i];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			d[j]=(mp[i][j]=judge(i,j))?1:d[j];
	for(int i=1;i<=m;i++)
		if(!d[i]){puts("-1");return 0;}
	while(l<=r){
		mid=l+r>>1;
		if(check(mid)) r=mid-1,ans=mid;
		else l=mid+1;
	}cout<<ans;return 0;
}
posted @ 2022-07-05 10:06  AIskeleton  阅读(9)  评论(0编辑  收藏  举报