1822: [JSOI2010]Frozen Nova 冷冻波
2013年4月01日 11:30
http://www.lydsy.com/JudgeOnline/problem.php?id=1822
RunID | User | Problem | Result | Memory | Time | Language | Code_Length | Submit_Time |
381251 | Liu_Ts | 1822 | Accepted | 2432 kb | 136 ms | C++ | 3298 B | 2013-04-01 11:22:43 |
题意
N个lich,M个spirit,每个lich有一个cd[i]和一个施法半径r[i];
K棵树,每棵树半径为R[i];
如果spirit在lich的施法半径内,且中间不经过任意一棵树,则可以打到。
每次施法只能打掉一个。
求最少多少时间可以打掉所有spirit。
题解
二分答案x,
网络流验证,
S向每个lich连边,容量为x/cd[i]+1
每个lich向它能打的到的spirit连边;
暴力预处理。
#include<cstring> #include<climits> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int K=202,N=500,M=100000; struct point { double x,y; point operator +(const point b) { point ans;ans.x=x+b.x;ans.y=y+b.y; return ans; } point operator -(const point b) { point ans;ans.x=x-b.x;ans.y=y-b.y; return ans; } double operator *(const point b) { double k=x*b.y-b.x*y; if((-1e-8)<k && k<(1e-8)) return 0; return k; } }lich[K],spirit[K],tree[K]; inline double dist(point a,point b) { point p=a-b; return sqrt(p.x*p.x+p.y*p.y); } inline double square(point a,point b,point c) { double k=(b-a)*(c-a); return abs(k); } int n,m,k,S,T; double Rlich[K],Tlich[K],Rtree[K]; bool can[K][K]; bool check(int p,int q) { if(Rlich[p]<dist(lich[p],spirit[q])) return 0; for(int i=1;i<=k;i++) { double l=square(lich[p],spirit[q],tree[i])/dist(lich[p],spirit[q]); if (Rtree[i]-l>(1e-8)) return 0; } return 1; } int init() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&lich[i].x,&lich[i].y,&Rlich[i],&Tlich[i]); for(int i=1;i<=m;i++) scanf("%lf%lf",&spirit[i].x,&spirit[i].y); for(int i=1;i<=k;i++) scanf("%lf%lf%lf",&tree[i].x,&tree[i].y,&Rtree[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(check(i,j)) can[i][j]=true; S=n+m+1;T=S+1; } int u[M],v[M],w[M],next[M],head[N],o; int low[N],d[N],vd[N],pre[N],cur[N]; void add(int x,int y,int z) { u[++o]=x;v[o]=y;w[o]=z;next[o]=head[x];head[x]=o; u[++o]=y;v[o]=x;w[o]=0;next[o]=head[y];head[y]=o; } int solve(int s,int t) { memset(cur,0,sizeof(cur)); memset(d,0,sizeof(d)); memset(vd,0,sizeof(vd)); int now=s,ans=0,i; vd[0]=t;low[s]=INT_MAX; while(d[s]<t) { for(i=cur[now];i;i=next[i]) if(w[i]>0&&d[now]==d[v[i]]+1) break; cur[now]=i; if(i) { pre[v[i]]=i;low[v[i]]=min(w[i],low[now]); now=v[i]; if(now==t) { for(;now!=s;now=u[pre[now]]) w[pre[now]]-=low[t],w[pre[now]^1]+=low[t]; low[s]=INT_MAX;ans+=low[t]; } } else { if(!--vd[d[now]]) break; d[now]=t; for(i=head[now];i;i=next[i]) if(w[i]>0&&d[now]>d[v[i]]+1) d[now]=d[v[i]]+1,cur[now]=i; vd[d[now]]++; if(now!=s) now=u[pre[now]]; } } return ans; } bool work(int x) { memset(head,0,sizeof(head));o=1; for(int i=1;i<=n;i++) { add(S,i,x/Tlich[i]+1); for(int j=1;j<=m;j++) if(can[i][j]) add(i,n+j,1); } for(int i=1;i<=m;i++) add(n+i,T,1); return solve(S,T)==m; } int main() { init(); int l=0,r=10000000,ans=-1; while(l<=r) { int mid=l+r>>1; if(work(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); }