bzoj1822

1822: [JSOI2010]Frozen Nova 冷冻波

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2080  Solved: 657
[Submit][Status][Discuss]

Description

WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。 在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。 现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?

Input

输入文件第一行包含三个整数N、M、K(N,M,K<=200),分别代表巫妖的数量、小精灵的数量和树木的数量。 接下来N行,每行包含四个整数x, y, r, t,分别代表了每个巫妖的坐标、攻击范围和施法间隔(单位为秒)。 再接下来M行,每行两个整数x, y,分别代表了每个小精灵的坐标。 再接下来K行,每行三个整数x, y, r,分别代表了每个树木的坐标。 输入数据中所有坐标范围绝对值不超过10000,半径和施法间隔不超过20000。

Output

输出一行,为消灭所有小精灵的最短时间(以秒计算)。如果永远无法消灭所有的小精灵,则输出-1。

Sample Input

2 3 1
-100 0 100 3
100 0 100 5
-100 -10
100 10
110 11
5 5 10

Sample Output

5

 

 

思路很简单的。每个witch向他能攻击到的精灵连一条容量1的边,每个精灵向T连容量1的边。

二分时间,得到witch的攻击次数。S向每个witch连接容量为攻击次数的边,判断最大流是不是=精灵个数

 

但是,,这道题的连边判断很蛋疼,要用很多几何知识。

 

代码写错了一些地方,懒得调了,先挂上

/*
爆炸
不想调了 
*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define inf 0x3f3f3f3f
#define ll long long
#define N 405
using namespace std;
int n,m,K,tot,S,T,pre,phd[N],hd[N],d[N],cur[N],vis[N];
struct witch{int x,y,r,t;}t[N];
struct ghost{int x,y;}p[N];
struct tree{int x,y,r;}tr[N];
struct edge{int v,next,cap;}e[N*N*2];
void adde(int u,int v,int c){
    e[tot].v=v;
    e[tot].next=hd[u];
    e[tot].cap=c;
    hd[u]=tot++;
}
bool bfs(){
    queue<int>q;
    memset(vis,0,sizeof(vis));
    d[S]=0;vis[S]=1;q.push(S);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=hd[u];~i;i=e[i].next){
            int v=e[i].v;
            if(e[i].cap&&!vis[v]){
                vis[v]=1;
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    return vis[T];
}
int dfs(int u,int a){
    if(u==T||!a)return a;
    int fl=0,f;
    for(int &i=cur[u];~i;i=e[i].next){
        int v=e[i].v;
        if(e[i].cap&&d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap,a)))){
            fl+=f;a-=f;e[i].cap-=f;
            e[i^1].cap+=f;if(!a)break;
        }
    }
    return fl;
}

int dinic(){
    int flow=0;
    while(bfs()){
        for(int i=S;i<=T;i++)cur[i]=hd[i];
        flow+=dfs(S,inf);
    }
    return flow;
}
int calc(int i,int j)
{return (p[j].x-t[i].x)*(p[j].x-t[i].x)+(p[j].y-t[i].y)*(p[j].y-t[i].y);}

struct vec{
    int x,y;
    vec res(){
        vec a=*this;
        a.x=-a.x;
        a.y=-a.y;
        return a;
    }
};
int dj(vec a,vec b){return a.x*b.x+a.y*b.y;}
int cj(vec a,vec b){return abs(a.x*b.y-b.x*a.y);}
bool check(int i,int j){
    for(int k=1;k<=K;k++){
        vec a=(vec){tr[k].x-t[i].x,tr[k].y-t[i].y};
        vec b=(vec){p[j].x-t[i].x,p[j].y-t[i].y};
        int sq=cj(a,b);
        double d=sqrt(calc(i,j));
        double h=sq/d/2;
        if(h>tr[k].r)continue;
        if(dj(a,b)<=0)continue;
        a=(vec){tr[k].x-p[j].x,tr[k].y-p[j].y};
        b=b.res();
        if(dj(a,b)>0)return 0;
    }
    return 1;
}

bool judge(int x){
    int sum=0;
    for(int i=0;i<tot;i++){
        if(i<pre){
            if(i&1)e[i].cap=0;
            else e[i].cap=1;
        }
        else{
            int id=(i-pre+1)/2+1;
            if(i&1)e[i].cap=0;
            else e[i].cap=x/t[id].t+1,sum+=x/t[id].t+1;
        }
    }
    if(sum<m)return 0;
    int flow=dinic();
    return flow==m;
}

int main(){
#ifdef wsy
    freopen("data.in","r",stdin);
#else
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
#endif
    memset(hd,-1,sizeof(hd));
    scanf("%d%d%d",&n,&m,&K);
    S=0;T=n+m+1;int mxt;
    for(int i=1;i<=n;i++)
    scanf("%d%d%d%d",&t[i].x,&t[i].y,&t[i].r,&t[i].t),mxt=max(mxt,t[i].t);
    for(int i=1;i<=m;i++)
    scanf("%d%d",&p[i].x,&p[i].y);
    for(int i=1;i<=K;i++)
    scanf("%d%d%d",&tr[i].x,&tr[i].y,&tr[i].r);
    int fg=0;
    for(int i=1;i<=m&&!fg;i++)
    for(int j=1;j<=K&&!fg;j++){
        int d=(p[i].x-tr[j].x)*(p[i].x-tr[j].x)+(p[i].y-tr[j].y)*(p[i].y-tr[j].y);
        if(d<=tr[j].r*tr[j].r)fg=1;
    }
    if(fg){puts("-1");return 0;}
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        int dis=calc(i,j);
        if(dis>t[i].r*t[i].r||!check(i,j))continue;
        adde(i,j+n,1);adde(j+n,i,0);//printf("%d %d %d\n",i,j+n,1);
    }
    for(int i=1;i<=m;i++)adde(i+n,T,1),adde(T,i+n,0)/*,printf("%d %d %d\n",i+n,T,1)*/;
    pre=tot;for(int i=1;i<=n;i++)adde(S,i,0),adde(i,S,0);
    int l=0,r=mxt*m,ans=-1;
    while(l<=r){
        int mid=l+r>>1;
        if(judge(mid)){
            r=mid-1;
            ans=mid;
        }
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}
posted @ 2017-11-30 07:56  _wsy  阅读(187)  评论(0编辑  收藏  举报