题目链接:点击查看

题目大意:给出一个二维平面坐标系,其中有n个巫师,m个敌人,以及k棵树,规定每个巫师都有一个攻击范围,可以攻击以巫师为圆心,以攻击范围为半径,形成的圆内的所有敌人,对于每棵树都有一个半径,规定以每棵树为圆心,以半径形成的圆都是障碍物,若巫师和敌人之间被至少一棵树遮挡(直线),则巫师无法攻击敌人,每个巫师的攻击都有冷却时间,现在问至少需要多长时间才能消灭所有敌人,若无法消灭所有敌人,输出-1

题目分析:题意不难懂,分析起来也比较简单,首先因为是在二维平面坐标系中处理问题,涉及到了平面几何的点及直线的关系,我直接套用了zx学长的几何模板,预处理出每个巫师可以攻击到的敌人,只要满足巫师和敌人之间没有任何树遮挡并且巫师和敌人的距离在巫师的攻击范围内就可以建立关系,在预处理时就可以顺便把-1的情况判断出来了,如果至少存在一个敌人无法和任何一个巫师匹配,那么就是-1的情况了,随后我们就可以直接二分了,因为每个巫师的攻击都有冷却时间,所以时间和消灭的敌人数显然保持着单调性,直接二分时间就好了,至于判断,我们可以用最大流,每次判断一下当前的时间下是否可以消灭全部敌人,因为在某个时间t下,每个巫师可以消灭的敌人是t/lich_time+1,+1是因为第一个敌人不需要冷却时间,这样我们如此建边:

  1. 源点->每个巫师,流量为可以消灭的敌人数
  2. 每个巫师->可消灭的敌人,流量为1
  3. 每个敌人->汇点,流量为1

就是一个简单的最大流,如此实现上述过程就是本题答案了

我是被一个小细节卡了半天,真的有点无语,就是在判断每棵树时,需要将其边界也算上(废话),就因为少了一个等号,WA了老半天了,自闭

再就是因为我码风的原因,可能代码看起来比较冗长,不过真的理解这个题目之后,实现起来并不是非常复杂的

代码:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const double eps=1e-8; const int N=410;bool vis[N];//标记敌人是否匹配struct Edge
{int to,w,next;
}edge[N*N];//边数int head[N],cnt,n,m,k;void addedge(int u,int v,int w)
{edge[cnt].to=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;//反向边边权设置为0edge[cnt].next=head[v];head[v]=cnt++;
}vector<int>node[N];//记录巫师与敌人的匹配情况int sgn(double x)//浮点型数值是否为 0
{if(abs(x)<eps) return 0;if(x<0) return -1; return 1;
}struct Point//二维点
{double x,y;Point(){}Point(double xx,double yy){ x=xx,y=yy;}Point operator - (const Point &b)const{ return Point(x-b.x,y-b.y); }double operator * (const Point &b)const { return x*b.x+y*b.y; }Point operator / (const double &k)const { return Point(x/k,y/k); }double operator ^ (const Point &b)const { return x*b.y-y*b.x; }//两点距离 double dis(const Point &b)const { return hypot(x-b.x,y-b.y); }
};struct Line
{Point s,e;Line(){}//两点Line(const Point ss,const Point ee){ s=ss,e=ee;}//求线段长度 double len() { return s.dis(e); }//点到直线的距离double dis_point_to_line(const Point &p) { return abs((p-s)^(e-s))/len(); }//点到线段的距离double dis_point_to_seg(const Point &p){if(sgn((p-s)*(e-s))<0||sgn((p-e)*(s-e))<0) return min(p.dis(s),p.dis(e)); return dis_point_to_line(p);}
};int d[N],now[N];//深度 当前弧优化bool bfs(int s,int t)//寻找增广路
{memset(d,0,sizeof(d));queue<int>q;q.push(s);now[s]=head[s];d[s]=1;while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(d[v])continue;if(!w)continue;d[v]=d[u]+1;now[v]=head[v];q.push(v);if(v==t)return true;}}return false;
}int dinic(int x,int t,int flow)//更新答案
{if(x==t)return flow;int rest=flow,i;for(i=now[x];i!=-1&&rest;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(w&&d[v]==d[x]+1){int k=dinic(v,t,min(rest,w));if(!k)d[v]=0;edge[i].w-=k;edge[i^1].w+=k;rest-=k;}}now[x]=i;return flow-rest;
}void init()//网络流初始化
{memset(now,0,sizeof(now));memset(head,-1,sizeof(head));cnt=0;
}int solve(int st,int ed)//网络流求解
{int ans=0,flow;while(bfs(st,ed))while(flow=dinic(st,ed,inf))ans+=flow;return ans;
}struct Liches
{double x,y,r;int t;void input(){scanf("%lf%lf%lf%d",&x,&y,&r,&t);}
}lich[N];//巫师struct Wisps
{double x,y;void input(){scanf("%lf%lf",&x,&y);}
}wisp[N];//敌人struct Tree
{double x,y,r;void input(){scanf("%lf%lf%lf",&x,&y,&r);}
}tree[N];//树bool check(Line L)//检查巫师和敌人之间是否被树遮挡
{for(int i=1;i<=k;i++){Point T(tree[i].x,tree[i].y);if(L.dis_point_to_seg(T)<=tree[i].r)//这个等号让我自闭了老半天return false;}return true;
}bool Init()//初始化巫师与敌人的关系
{memset(vis,false,sizeof(vis));for(int i=1;i<=n;i++){node[i].clear();Point L(lich[i].x,lich[i].y);for(int j=1;j<=m;j++){Point W(wisp[j].x,wisp[j].y);if(L.dis(W)>lich[i].r)continue;if(check(Line(L,W))){node[i].push_back(j);vis[j]=true;}}}for(int i=1;i<=m;i++)//顺便判断-1的情况if(!vis[i])return false;return true;
}bool cal(int x)//用网络流判断当前时间是否可行
{init();int st=N-1,ed=st-1;for(int i=1;i<=n;i++){int time=x/lich[i].t+1;addedge(st,i,time);for(int j=0;j<node[i].size();j++)addedge(i,node[i][j]+n,1);}for(int i=1;i<=m;i++)addedge(i+n,ed,1);return solve(st,ed)==m;
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);int w;cin>>w;while(w--){scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)lich[i].input();for(int i=1;i<=m;i++)wisp[i].input();for(int i=1;i<=k;i++)tree[i].input();if(!Init()){puts("-1");continue;}int l=0,r=inf,ans=-1;while(l<=r)//二分时间{int mid=l+r>>1;if(cal(mid)){ans=mid;r=mid-1;}elsel=mid+1;}printf("%d\n",ans);}return 0;
}

HDU - 3126 Nova(最大流+二分+简单几何)相关推荐

  1. python画三维几何图-Python下opencv使用笔记(二)(简单几何图像绘制)

    简单几何图像一般包含点.直线.矩阵.圆.椭圆.多边形等等.首先认识一下opencv对像素点的定义. 图像的一个像素点有1或者3个值.对灰度图像有一个灰度值,对彩色图像有3个值组成一个像素值.他们表现出 ...

  2. python输入输出简单例子_Python 文件和流的简单示例

    这篇文章主要为大家详细介绍了Python 文件和流的简单示例,具有一定的参考价值,可以用来参考一下. 对python这个高级语言感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! 1.打开文 ...

  3. HDU 1576 A/B(数论简单题,求逆元)

    A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  4. Python下opencv使用笔记(二)(简单几何图像绘制)

    简单几何图像一般包括点.直线.矩阵.圆.椭圆.多边形等等.首先认识一下opencv对像素点的定义.图像的一个像素点有1或者3个值,对灰度图像有一个灰度值,对彩色图像有3个值组成一个像素值,他们表现出不 ...

  5. 【计算机图形学实验四——简单几何形体的平移、缩放、旋转等几何变换】

    一.实验内容.目的.要求 1.简单几何形体(三角形.多边形等)的平移.缩放.旋转等几何变换. 2.掌握相关算法的原理及实现 3.实现基础代码(非调用OpenGL等图形库): 缩放.旋转等能指定变换参考 ...

  6. Storm之——流组件简单串行编程实践

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/78447229 Storm是一个分布式是实时计算系统,它设计了一种对流和计算的抽象, ...

  7. 2021牛客暑期多校训练营2 F Girlfriend (阿波罗尼斯圆+简单几何)

    F Girlfriend (阿波罗尼斯球+简单几何) 题目大意: 给定四个点,每两个点构成一个阿波罗尼斯球,求两圆相交部分的体积. 思路: 一看就是几何题啊,话不多说直接开淦... 首先对于阿波罗尼斯 ...

  8. HDU - 3081 Marriage Match II(二分+并查集+最大流/匈牙利删边)

    题目链接:点击查看 题目大意:n个男生和n个女生配对,配对规则如下: 每个女生都可以选择没有吵过架的男生匹配 若女生A的好朋友是女生B,且女生B没有和男生C吵过架,则女生A也可以和男生C匹配 现在问最 ...

  9. 二分图带权最大匹配费用流_简单理解二分图与匈牙利算法

    最近在看DETR等论文时时,看到了使用了二分图的最大匹配,对于没有计算机基础的我表示直接上来???,因此本篇博客主要介绍什么是二分图,以及二分图的匹配的匈牙利算法. 首先我们来看看二分图的定义: 二分 ...

最新文章

  1. 设计模式笔记(1)---开篇(文章索引)
  2. 公布.NET 框架库源代码(转)
  3. 数据集与JSON对象互相转换
  4. 《React Native移动开发实战》一一3.4 完善商品列表——ListView组件
  5. 服务器flask远程访问_在Flask中使用什么API来检查远程(其他)服务器的连接?...
  6. linux磁盘分区表解读:只占64字节
  7. 编程语言50年来的变化,我用50种编程语言告诉你“Hello world”怎么写!
  8. c语言中把一个数缩小十倍_C语言实例第04期,在控制台打印出著名的杨辉三角...
  9. URL 中,查询字符串与HTML实体冲突,可能带来的问题.
  10. python分支和循环的思维导图_思维导图的绘制步骤【PDCA管理循环】
  11. iOS使用得图SDK开发VR播放器
  12. Matlab在线运行网站
  13. ZXing源码解析四:如何识别图片中的二维码
  14. 【题解】模拟赛11.22 T4 星际战争
  15. MSSQL2008 性能优化
  16. winpe装双系统linux_制作win7+ubuntu +winPE+CDlinux多系统启动U盘
  17. eclipse上插入中文到mysql,但是navicat显示问号《网上很多方法都没用》,最终google到了精品
  18. 部署-GPS授时系统:GPS授时系统
  19. 【python黑帽子】——(一)搭建扫描器入门介绍
  20. wireshark分析数据包

热门文章

  1. RabbitMQ异步发布确认
  2. 为什么要Zipkin
  3. 如何开启需要的垃圾收集器
  4. Spring 核心容器类BeanFactory
  5. 反射获取构造方法并使用【应用】
  6. MybatisPlus添加操作
  7. HttpCLient工具使用讲解
  8. java 文本 从列开始_如何从sql java中检索文本列?
  9. Spring Cloud Gateway 源码解析(4)-- filter
  10. NIO--Channel