[BZOJ 1822][JSOI2010]Frozen Nova 冷冻波:最大流

来源:互联网 发布:淘宝一折特卖网 编辑:程序博客网 时间:2024/04/28 00:49

点击这里查看原题

首先暴力判断哪些巫妖可以打到哪些小精灵,先判距离是否小于半径,然后判断树是否阻挡。判断树的方法是先计算出巫妖和小精灵连线的一般式ax+by+c=0,然后据此计算树的圆心到两点连线的距离dis=|ax+by+x|a2+b2,是否小于树的半径。
接下来就是二分时间time,源点与所有巫妖之间连容量为time/t+1的边,巫妖和能打到的精灵之间连容量为1的边,精灵和汇点连容量为1的边。然后跑最大流看最大流是不是m

/*User:SmallLanguage:C++Problem No.:1822*/#include<bits/stdc++.h>#define ll long long#define inf 999999999using namespace std;int n,m,t,tot,fir[405],dep[405];bool can[205],ok[205][205];struct edge{    int v,w,nex;}e[100005];struct witch{    int x,y,r,t;}wy[205];struct elf{    int x,y;}jl[205];struct tree{    int x,y,r;}sh[205];int sqr(int x){    return x*x;}void add(int u,int v,int w){    e[++tot]=(edge){v,w,fir[u]};    fir[u]=tot;    e[++tot]=(edge){u,0,fir[v]};    fir[v]=tot;}bool bfs(int s,int t){    memset(dep,-1,sizeof(dep));    dep[s]=0;    queue<int> q;    q.push(s);    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=fir[u];i;i=e[i].nex){            int v=e[i].v;            if(e[i].w&&dep[v]==-1){                dep[v]=dep[u]+1;                q.push(v);            }        }    }    return dep[t]!=-1;}int dfs(int u,int f,int t){    if(u==t) return f;    int sum=0;    for(int i=fir[u];i;i=e[i].nex){        int v=e[i].v;        if(e[i].w&&dep[v]==dep[u]+1){            int d=dfs(v,min(f,e[i].w),t);            sum+=d;            f-=d;            e[i].w-=d;            e[i^1].w+=d;            if(!f) return sum;        }    }    if(sum==0) dep[u]=-1;    return sum;}int dinic(int s,int t){    int res=0;    while(bfs(s,t)){        res+=dfs(s,inf,t);    }    return res;} bool check(int t){    tot=1;    memset(fir,0,sizeof(fir));    for(int i=1;i<=n;i++){        add(1,i+2,t/wy[i].t+1);        for(int j=1;j<=m;j++) if(ok[i][j]) add(2+i,2+n+j,1);    }    for(int i=1;i<=m;i++) add(2+n+i,2,1);    return dinic(1,2)==m;}int main(){    freopen("data.in","r",stdin);//    scanf("%d%d%d",&n,&m,&t);    for(int i=1;i<=n;i++) scanf("%d%d%d%d",&wy[i].x,&wy[i].y,&wy[i].r,&wy[i].t);    for(int i=1;i<=m;i++) scanf("%d%d",&jl[i].x,&jl[i].y);    for(int i=1;i<=t;i++) scanf("%d%d%d",&sh[i].x,&sh[i].y,&sh[i].r);    for(int i=1;i<=n;i++){        int ax=wy[i].x,ay=wy[i].y;        for(int j=1;j<=m;j++){            int bx=jl[j].x,by=jl[j].y;            if(sqr(ax-bx)+sqr(ay-by)>sqr(wy[i].r)) continue;            int a=by-ay,b=ax-bx,c=ay*bx-by*ax;//计算巫妖和小精灵的连线的一般式ax+by+c=0            double d=sqrt(sqr(a)+sqr(b));            bool flag=0;            for(int k=1;k<=t;k++){                double dis=fabs(a*sh[k].x+b*sh[k].y+c)/d;                if(dis<sh[k].r){                    flag=1;                    break;                }            }            if(!flag){                can[j]=1;                ok[i][j]=1;            }        }    }    for(int i=1;i<=m;i++)        if(!can[i]){            printf("-1\n");            return 0;        }    int l=0,r=4e6,mid;    while(l<=r){        mid=l+r>>1;        if(check(mid)) r=mid-1;        else l=mid+1;    }    printf("%d\n",r+1);    return 0;}