其他分享
首页 > 其他分享> > 冷冻波

冷冻波

作者:互联网

[JSOI2010]冷冻波

传送门:题目传送门

题目描述

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

样例输入 #1

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

样例输出 #1

5

思路:暴力枚举 + 计算几何 + 二分 + 网络流

暴力枚举

先枚举判断每个精灵都能被谁杀死,用二维数组存状态,
遇到不能被杀死的精灵就输出 -1 结束。


几何

判断过程中先看有没有树:

没树

就直接判断巫妖能不能攻击到精灵。

有树

用点到直线距离算出距离和垂足,判断垂足在不在巫妖和精灵之间;如果不在 就直接判断巫妖能不能攻击到精灵;如果在 比较树的半径和距离;


二分

在0~最短的杀死所有精灵的时间内,杀死精灵数随时间单调递增,则可以二分最短的杀死所有精灵的时间。


网络流检验

符合最大流的流量守恒和容量限定,求最多杀死的精灵数的最大流。

建图:源点到巫妖建边,容量为可杀死精灵数;精灵到汇点建边,容量为 1;巫妖到可杀死的精灵建边,容量为 1;

建完图之后,跑一遍 dinic 检验答案。


代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
const int N=10010,M=200010,inf=1e8;
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,k,S,T;
int q[N],h[N],e[M],f[M],ne[M],cur[N],d[N],idx;
bool kill[600][600];

struct node
{
    double x,y,r,t;
}lich[N],wisp[M],tree[N];

void add(int a,int b,int c)
{
    e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
    e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}

bool bfs()
{
    int tt=0,hh=0;
    memset(d,-1,sizeof d);
    q[0]=S,d[S]=0,cur[S]=h[S];
    while(hh<=tt)
    {
        int t=q[hh++];
        for(int i=h[t];~i;i=ne[i])
        {
            int ver=e[i];
            if(d[ver]==-1&&f[i])
            {
                d[ver]=d[t]+1;
                cur[ver]=h[ver];
                if(ver==T) return true;
                q[++tt]=ver;
            }
        }
    }
    return false;
}
int find(int u,int limit)
{
    if(u==T) return limit;
    int flow=0;
    for(int i=cur[u];~i&&flow<limit;i=ne[i])
    {
        cur[u]=i;
        int ver=e[i];
        if(d[ver]==d[u]+1&&f[i])
        {
            int t=find(ver,min(limit-flow,f[i]));
            if(!t) d[ver]=-1;
            f[i]-=t,f[i^1]+=t,flow+=t;
        }
    }
    return flow;
}
int dinic()
{
    int ans=0,t;
    while(bfs()) ans+=find(S,inf);
    return ans;
}
bool check(int mid)
{
    memset(h,-1,sizeof h);
    S=0;idx=0;T=n+m+1;
    for(int i=1;i<=n;i++)
    {
        add(S,i,mid/lich[i].t+1);//源点到巫妖建边,容量为可杀死的精灵数 
    }
    for(int i=1;i<=m;i++)
    {
        add(i+n,T,1);//精灵到汇点建边,容量为 1
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(kill[i][j])
            {
                add(i,j+n,1);//巫妖到可杀死的精灵建边,容量为1
            }
        }
    }
   
    return dinic()>=m;
}

bool pd(node a,node b,node c,bool ok)
{
    if(ok)//没树 
    {
        if(a.r*a.r<(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)) return false;// 直接判断能不能攻击到 
	else true;
    }
    else//有树 
    {
	if(a.r*a.r<(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)) return false; //先判断能不能攻击到 
        ll A=b.y-a.y,
           B=a.x-b.x,
           C=b.x*a.y-a.x*b.y;
        if(c.r&&(A*c.x+B*c.y+C)*(A*c.x+B*c.y+C)>=(A*A+B*B)*c.r*c.r) return true;//如果能攻击到再判断树会不会挡住 
        else
        {
            int xi=(B*B*c.x-A*B*c.y-A*C),yi=(-A*B*c.x+A*A*c.y-B*C)/(A*A+B*B),temp=(A*A+B*B);//处理树到直线的垂点不在巫妖和精灵之间 
            if((a.y<yi&&yi<b.y)||(b.y<yi&&yi<a.y)) return false;
            else return true;
        }
    }
    
}
int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)
    {
        lich[i].x=read(),lich[i].y=read(),lich[i].r=read(),lich[i].t=read();
    }
    for(int i=1;i<=m;i++)
    {
        wisp[i].x=read(),wisp[i].y=read();
    }
    for(int i=1;i<=k;i++)
    {
        tree[i].x=read(),tree[i].y=read(),tree[i].r=read();
    }
        
    for(int i=1;i<=n;i++)//暴力枚举存储攻击关系 
    {
        for(int j=1;j<=m;j++)
        {
            bool flag=true,ok=0;
            int g;
            if(k==0) g=0,ok=1;
            else g=1;
                
            for(;g<=k;g++)
            {
                if(!pd(lich[i],wisp[j],tree[g],ok))
                {
                    flag=false;
                    break;
                }
            }
            kill[i][j]=flag;
        }
    }
      
  
       
    for(int i=1;i<=m;i++)//如果有精灵死不了就输出-1 
    {
	bool flag=false;
	for(int j=1;j<=n;j++)
	{
	    if(kill[j][i]) flag=true;
	}
	if(!flag)
        {
            puts("-1");return 0;
        }
    }
      
    int L=0,R=1e9,mid,res=-1;//二分最短的杀死所有精灵的时间 
    while(L<R)
    {
        mid=(L+R)>>1;
        if(check(mid)) R=mid;
	else L=mid+1;
    }
    printf("%d\n",R); 
    
    return 0;
}

标签:ch,idx,int,精灵,小精灵,杀死,冷冻
来源: https://www.cnblogs.com/watasky/p/16446790.html