bzoj 1822 冷冻波
题目大意:
在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵
我们认为,巫妖和小精灵都可以看成是平面上的点。
当巫妖和小精灵之间的直线距离不超过R,且巫妖和小精灵的连线与任何树木都没有公共点,巫妖就可以瞬间杀灭一个小精灵。
在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放
不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。
若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵
思路:
最大流建图还是比较好想的
但是答案需要二分,然后用最大流判断
连边的时候每个巫妖和它可以消灭的小精灵连一条流量为一的边
每个小精灵和超级汇连一条流量为1的边
每个巫妖和超级源连一条时间(二分得到)/冷却时间+1的流量的边
但是如何判断哪些巫妖和小精灵之间连边呢
需要计(jie)算(xi)几何判断
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 420 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); 19 return x*f; 20 } 21 int n,m,k,r[MAXN],cd[MAXN],R[MAXN],d[MAXN]; 22 struct node {int x,y;}g[MAXN],h[MAXN],tr[MAXN]; 23 double dis(int x1,int y1,int x2,int y2) {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));} 24 int check(node a,node b,int i) 25 { 26 if(dis(a.x,a.y,b.x,b.y)>=r[i]) return 0; 27 int A=b.y-a.y,B=a.x-b.x,C=b.x*a.y-a.x*b.y; 28 for(int l=1;l<=k;l++) 29 { 30 double dst=fabs(A*tr[l].x+B*tr[l].y+C)/sqrt(A*A+B*B); 31 double k1,b1,b2,b3; 32 if(a.x==b.x) b1=a.y,b2=b.y,b3=tr[l].y; 33 else if(a.y==b.y) b1=a.x,b2=b.x,b3=tr[l].x; 34 else k1=B/A,b1=a.y-k1*a.x,b2=b.y-k1*b.x,b3=tr[l].y-k1*tr[l].x; 35 if((b3-b1)*(b3-b2)<=0) if(dst<=R[l]) return 0; 36 if(abs(b3-b1)>abs(b3-b2)) if(dis(b.x,b.y,tr[l].x,tr[l].y)<=R[l]) return 0; 37 else if(dis(a.x,a.y,tr[l].x,tr[l].y)<=R[l]) return 0; 38 } 39 return 1; 40 } 41 struct dinic 42 { 43 int fst[MAXN],nxt[MAXN*MAXN],to[MAXN*MAXN],val[MAXN*MAXN],mp[MAXN][MAXN],cnt,s,t; 44 void mem() {memset(fst,0xff,sizeof(fst));cnt=-1;} 45 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 46 void build(int x) 47 { 48 mem(); 49 for(int i=1;i<=n;i++) {add(s,i,x/cd[i]+1);add(i,s,0);} 50 for(int i=1;i<=m;i++) {add(n+i,t,1);add(t,n+i,0);} 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=m;j++) 53 if(mp[i][j]) {add(i,n+j,1);add(n+j,i,0);} 54 } 55 int vis[MAXN],tot,cur[MAXN],dep[MAXN],q[MAXN]; 56 int bfs() 57 { 58 int l=1,r=0; 59 memset(dep,0xff,sizeof(dep)); 60 vis[t]=++tot,q[++r]=t; 61 while(l<=r) 62 { 63 int x=q[l++]; 64 for(int i=fst[x];i!=-1;i=nxt[i]) 65 if(val[i^1]&&vis[to[i]]!=tot) 66 { 67 vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i]; 68 if(to[i]==s) return 1; 69 } 70 } 71 return vis[s]==tot; 72 } 73 int dfs(int x,int a) 74 { 75 if(x==t||!a) return a; 76 int flow=0,f; 77 for(int& i=cur[x];i!=-1;i=nxt[i]) 78 { 79 if(val[i]&&dep[to[i]]==dep[x]-1&&(f=dfs(to[i],min(a,val[i])))) 80 { 81 val[i]-=f,val[i^1]+=f,flow+=f,a-=f; 82 if(!a) break; 83 } 84 } 85 return flow; 86 } 87 int solve() 88 { 89 int ans=0;int f; 90 while(bfs()) 91 { 92 for(int i=0;i<=n+m+1;i++) cur[i]=fst[i]; 93 while(f=dfs(s,inf)) ans+=f; 94 } 95 return ans; 96 } 97 }D; 98 int main() 99 { 100 n=read(),m=read(),k=read();int mx=-1; 101 for(int i=1;i<=n;i++) g[i].x=read(),g[i].y=read(),r[i]=read(),cd[i]=read(),mx=max(mx,cd[i]); 102 for(int i=1;i<=m;i++) {h[i].x=read(),h[i].y=read();D.add(n+i,n+m+2,1);D.add(n+m+2,n+i,0);} 103 for(int i=1;i<=k;i++) tr[i].x=read(),tr[i].y=read(),R[i]=read(); 104 D.s=0,D.t=n+m+1;int f; 105 for(int j=1;j<=m;j++) 106 { 107 f=0; 108 for(int i=1;i<=n;i++) 109 { 110 D.mp[i][j]=check(g[i],h[j],i); 111 if(D.mp[i][j]) f=1; 112 } 113 if(!f) {puts("-1");return 0;} 114 } 115 int l=0,r=m*mx,mid; 116 int ans=inf; 117 while(l<=r) 118 { 119 mid=(l+r)>>1; 120 D.build(mid); 121 if(D.solve()==m) ans=min(ans,mid),r=mid-1; 122 else l=mid+1; 123 } 124 printf("%d",ans); 125 }
对于计算几何非常不熟练,只能用解析几何
写完的时候因为忘记了有n+m+2个点调了好久以及循环的时候把循环的变量写没了