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);
}