ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

冷冻波

2022-07-05 16:04:56  阅读:137  来源: 互联网

标签:ch idx int 精灵 小精灵 杀死 冷冻


[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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有