BZOJ1822[JSOI2010] 冷冻波

23 篇文章 0 订阅
13 篇文章 0 订阅

luogu链接:https://www.luogu.org/problemnew/show/P4048
bzoj链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1822

冷冻波

题目描述

WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。

当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。

在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。

现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?

输入输出格式
输入格式:

输入文件第一行包含三个整数N、M、K(N,M,K<=200),分别代表巫妖的数量、小精灵的数量和树木的数量。

接下来N行,每行包含四个整数x, y, r, t,分别代表了每个巫妖的坐标、攻击范围和施法间隔(单位为秒)。

再接下来M行,每行两个整数x, y,分别代表了每个小精灵的坐标。

再接下来K行,每行三个整数x, y, r,分别代表了每个树木的坐标。

输入数据中所有坐标范围绝对值不超过10000,半径和施法间隔不超过20000。

输出格式:

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

输入输出样例
输入样例#1:

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

输出样例#1:

5

题解

用计算几何求解巫妖和精灵间能否互相到达并以此建图,然后二分时间跑二分图匹配不断更新答案即可AC。

细节

注意先判断-1的情况,二分上界取maxcd*m,即冷却时间最长的巫妖单独杀死所有精灵的情况。更新时间后重新建图,超级源点到每个巫妖的边流量取time/cd[i]+1,即总时间除以冷却时间+1(因为在time=0的时候巫妖可以发射第一发Frozen Nova),其余边流量都为1。  

代码略长大家实现的时候耐心一点,其实就是计算几何+dinic没什么思维难度,主要考代码实现。

另外,洛谷上第三个点博主的裸dinic被卡T了,加个当前弧优化快了500ms,把inline去掉又快了200ms(迷。。。),bzoj无压力过。

代码
#include<bits/stdc++.h>
#define db double
#define R register
using namespace std;
const int M=50005;
const db eps=1e-8;
struct edge{int to,fl;};
struct pt{int x,y,r;};
int sig(db x){return (x>eps)-(x<-eps);}
db dis(pt a,pt b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)*1.0);}
int operator * (pt a,pt b){return a.x*b.y-a.y*b.x;}
pt operator - (pt a,pt b){return (pt){a.x-b.x,a.y-b.y};}
db dis(pt p,pt a,pt b){return abs((a-p)*(b-p)*1.0/dis(a,b));}
pt lich[M],elv[M],tree[M];
edge ed[1000005];
vector<int>x[M];
int d[M],g=0,maxcd,cd[M],s,e,n,m,k,f;
bool vis[M];
char c;
void read(int &r)
{
    r=0;f=1;c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(isdigit(c))r=(r<<1)+(r<<3)+c-'0',c=getchar();
    r*=f;
}
void add(int a,int b)
{
    ed[g]=(edge){b,1};
    x[a].push_back(g++);
    ed[g]=(edge){a,0};
    x[b].push_back(g++);
}
int bfs(int s,int e)
{
    R int i;
    memset(d,0,sizeof(d));
    queue<int>dui;
    dui.push(s);
    d[s]=1;
    int f,hh,t;
    while(!dui.empty())
    {
        f=dui.front();
        dui.pop();
        for(i=x[f].size()-1;i>=0;--i)
        {
            hh=x[f][i];
            t=ed[hh].to;
            if(d[t]||!ed[hh].fl)continue;
            d[t]=d[f]+1;
            dui.push(t);
        }
    }
    return d[e];
}
int dfs(int s,int e,int minn)
{
    R int i;
    if(s==e||!minn)return minn;
    int ans=0,hh,fl,to,tmp;
    for(i=x[s].size()-1;i>=0;--i)
    {
        hh=x[s][i];
        fl=ed[hh].fl;
        to=ed[hh].to;
        if(d[to]!=d[s]+1||!fl)continue;
        tmp=dfs(to,e,min(minn-ans,fl));
        if(!tmp)continue;
        ed[hh].fl-=tmp;
        ed[hh^1].fl+=tmp;
        ans+=tmp;
        if(minn==tmp)break;
    }
    return ans;
}
int dinic()
{
    int ans=0;
    while(bfs(e,s))
    ans+=dfs(e,s,1e9);
    return ans;
}
void reb(int t)
{
    R int i;
    int hh;
    for(i=0;i<g;i+=2)
    ed[i].fl=1,ed[i+1].fl=0;
    for(i=x[0].size()-1;i>=0;--i)
    ed[x[0][i]^1].fl=t/cd[ed[x[0][i]].to]+1;
}
void in()
{
    R int i;
    read(n);read(m);read(k);
    e=n+m+1;
    for(i=1;i<=n;++i)
    read(lich[i].x),read(lich[i].y),read(lich[i].r),read(cd[i]),maxcd=max(maxcd,cd[i]);
    for(i=1;i<=m;++i)
    read(elv[i].x),read(elv[i].y);
    for(i=1;i<=k;++i)
    read(tree[i].x),read(tree[i].y),read(tree[i].r);
}
bool check(pt a,pt b)
{
    R int i;
    if(sig(dis(a,b)-a.r)>0) return 0;
    for(i=1;i<=k;++i)
    {
        if(sig(dis(a,tree[i])-tree[i].r)<0)return 0;
        if(sig(dis(b,tree[i])-tree[i].r)<0)return 0;
        if((dis(tree[i],a,b)-tree[i].r)<0)return 0;
    }
    return 1;
}
void build()
{
    R int i,j;
    for(i=1;i<=n;++i)
    add(i,0);
    for(i=1;i<=n;++i)
    for(j=1;j<=m;++j)
    if(check(lich[i],elv[j]))
    {
        add(j+n,i);
        vis[j]=1;
    }
    for(i=1;i<=m;++i)
    add(n+m+1,n+i);
    for(i=1;i<=m;++i)
    if(!vis[i])
    {
        printf("-1");
        exit(0);
    }
}
void ac()
{
    int le=0,ri=m*maxcd,mid,ans,p;
    while(le<=ri)
    {
        mid=(le+ri)>>1;
        reb(mid);
        p=dinic();
        if(p==m)
        {
            ans=mid;
            ri=mid-1;
        }
        else le=mid+1;
    }
    printf("%d",ans);
}
int main()
{
    in();build();ac();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值