题意: 有n 个小巫师,还有 m 个小精灵 ,还有 K 个大树,巫师可以用 霜冻新星杀死小精灵,但是每使用一次都有一定
的技能冷却时间,而且小精灵必须在攻击范围内。
分析: 二分答案,即枚举符合条件的时间,满足所有小精灵被KO,由于每个巫师能够杀死多个小精灵,所以可以用到二分
图多重匹配,如果所有小精灵都找到匹配,那么该时间符合, 最麻烦的是建图,两个人之间必须不能有树阻挡,在
计算两个人所在线段与 树相交的时候 可以先计算点(树的坐标)到线段(巫师与小精灵连线)的最短距离,如果该
距离小于树的半径,那么该巫师和小精灵能够形成匹配。
View Code
#include<stdio.h> #include<string.h> #include<math.h> #define clr(x) memset(x,0,sizeof(x)) int cap; int map[202][202]; int link[202][202]; int vlink[202]; int v[202]; int tot; int n,m,K; double lx[202],ly[202],lr[202]; int t[202]; double tx[202],ty[202],tr[202]; double wx[202],wy[202]; int find(int x) { int i,j; for(i=0;i<n;i++) { if(map[x][i]&&!v[i]) { v[i]=1; if(t[i]==0||vlink[i]<=cap/t[i]) { link[i][vlink[i]++]=x; return 1; } for(j=0;j<vlink[i];j++) if(find(link[i][j])) { link[i][j]=x; return 1; } } } return 0; } bool ok() { int i,sum=0; clr(vlink); for(i=0;i<m;i++) { clr(v); if(find(i)) sum++; else break; } if(sum==m) return 1; return 0; } double dis(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double mul(double x1,double y1,double x2,double y2) { return x1*y2-x2*y1; } double fa(double x) { return x>0?x:-1*x; } bool sec(int i,int j,int k) { double s=fa(mul(wx[j]-lx[i],wy[j]-ly[i],tx[k]-lx[i],ty[k]-ly[i])); double t1=dis(lx[i],ly[i],tx[k],ty[k]); double t2=dis(wx[j],wy[j],tx[k],ty[k]); double t3=dis(lx[i],ly[i],wx[j],wy[j]); double dd=s/t3; double tm1=sqrt(t1*t1-dd*dd); double tm2=sqrt(t2*t2-dd*dd); double d; if(tm1>t3||tm2>t3) { if(t1>t2) d=t2; else d=t1; } else d=dd; if(d<=tr[k]) return true; return false; } bool in(int i,int j) { if(dis(lx[i],ly[i],wx[j],wy[j])<=lr[i]) return true; return false; } int main() { //freopen("D:ce.txt","r",stdin); int i,j,k,T,low,high,tmp; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&K); tmp=0; for(i=0;i<n;i++) { scanf("%lf%lf%lf%d",&lx[i],&ly[i],&lr[i],&t[i]); if(t[i]>tmp) tmp=t[i]; } for(i=0;i<m;i++) scanf("%lf%lf",&wx[i],&wy[i]); for(i=0;i<K;i++) scanf("%lf%lf%lf",&tx[i],&ty[i],&tr[i]); clr(v); clr(map); for(i=0;i<n;i++) for(j=0;j<m;j++) { if(in(i,j)) { for(k=0;k<K;k++) if(sec(i,j,k)) break; if(k==K) { v[j]=1; map[j][i]=1; } } } for(i=0;i<m;i++) if(!v[i]) break; if(i!=m) { printf("-1\n"); continue; } low=0; high=tmp*m; while(low<high) { cap=(low+high)>>1; if(ok()) high=cap; else low=cap+1; } printf("%d\n",low); } return 0; }