【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)
【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)
题面
题解
很明显需要二分一个答案。
那么每个点可以确定的范围就是以当前点为圆心,二分出来的答案为半径画一个圆,和目标的圆的交就是可行的区间。
首先我们不知道正\(n\)边形的转角,如果我们知道的话,可以直接暴力网络流来进行\(check\)。
首先一个答案可行,意味着某个点在目标圆上覆盖的弧的两端中,一定有一个是可行的。
所以我们需要验证的转角只有\(2n\)个。这样子暴力跑网络流的次数是\(2nlogn\)次。
考虑如何优化这个过程。
发现合法的转角一共\(2n\)个,把它们按照转角排序,考虑从小往大改变转角的过程,显然每次会删掉一个可行的匹配,或者是加入一组可行的匹配。
那么这里删边直接退流就好了,不需要每次构图重建。
因为是二分图,退流直接手动删边就行了。
加边直接加完之后重新增广一次就行了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX 605
const double Pi=acos(-1),eps=1e-8;
const int inf=1000000000;
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,R,S,T;
struct Line{int v,next,w;}e[MAX*MAX];
int h[MAX],cnt=2,cur[MAX];
inline void Add(int u,int v,int w)
{
e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
e[cnt]=(Line){u,h[v],0};h[v]=cnt++;
}
int level[MAX];
bool bfs()
{
for(int i=S;i<=T;++i)level[i]=0;
for(int i=S;i<=T;++i)cur[i]=h[i];
queue<int> Q;level[S]=1;Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=h[u];i;i=e[i].next)
if(e[i].w&&!level[e[i].v])
level[e[i].v]=level[u]+1,Q.push(e[i].v);
}
return level[T];
}
int dfs(int u,int flow)
{
if(u==T||!flow)return flow;
int ret=0;
for(int &i=cur[u];i;i=e[i].next)
{
int v=e[i].v,d=0;
if(e[i].w&&level[v]==level[u]+1)
{
d=dfs(v,min(flow,e[i].w));
ret+=d;flow-=d;
e[i].w-=d;e[i^1].w+=d;
if(!flow)break;
}
}
if(!flow)level[u]=0;
return ret;
}
void Delete(int u,int v,int &flow)
{
int val=0;
for(int i=h[v],j=0;i;j=i,i=e[i].next)
if(e[i].v==u){j?(e[j].next=e[i].next):(h[v]=e[i].next);break;}
for(int i=h[u],j=0;i;j=i,i=e[i].next)
if(e[i].v==v){j?(e[j].next=e[i].next):(h[u]=e[i].next);val=e[i].w^1;break;}
if(!val)return;--flow;
for(int i=h[S];i;i=e[i].next)if(e[i].v==u){e[i].w^=1,e[i^1].w^=1;break;}
for(int i=h[T];i;i=e[i].next)if(e[i].v==v){e[i].w^=1,e[i^1].w^=1;break;}
if(bfs())flow+=dfs(S,inf);
}
struct Point{double x,y;}p[MAX];
struct Degree{double t;int u,v,opt;}q[MAX];
bool operator<(Degree a,Degree b){return a.t!=b.t?a.t<b.t:a.opt>b.opt;}
double alpha;
bool check(double mid)
{
for(int i=S;i<=T;++i)h[i]=0;cnt=2;
int tot=0;
for(int i=1;i<=n;++i)
{
double dis=sqrt(p[i].x*p[i].x+p[i].y*p[i].y);
if(dis>R+mid||dis<R-mid)return false;
if(dis+R<=mid)
for(int j=1;j<=n;++j)Add(i,j+n,1);
else
{
double ang=atan2(p[i].y,p[i].x);
double d=acos((1.0*R*R+dis*dis-mid*mid)/(2*R*dis));
double l=ang-d,r=ang+d;
while(l<0)l+=2*Pi;while(r<0)r+=2*Pi;
int L=l/alpha,R=r/alpha;
q[++tot]=(Degree){l-L*alpha,i,L+1,1};
q[++tot]=(Degree){r-R*alpha,i,R+1,-1};
++L,++R;
if(l<=r)
for(int j=L+1;j<=R;++j)Add(i,j+n,1);
else
{
for(int j=L+1;j<=n;++j)Add(i,j+n,1);
for(int j=1;j<=R;++j)Add(i,j+n,1);
}
}
}
for(int i=1;i<=n;++i)Add(S,i,1),Add(i+n,T,1);
sort(&q[1],&q[tot+1]);int ans=0;
while(bfs())ans+=dfs(S,inf);
if(ans==n)return true;
for(int i=1;i<=tot;++i)
if(q[i].opt==1)
{
Add(q[i].u,q[i].v+n,1);
if(bfs())ans+=dfs(S,inf);
if(ans==n)return true;
}
else Delete(q[i].u,q[i].v+n,ans);
return false;
}
int main()
{
n=read();R=read();alpha=2*Pi/n;
S=0;T=n+n+1;
for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
double l=0,r=400;
while(r-l>eps)
{
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
printf("%.8lf\n",l);
return 0;
}
【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)的更多相关文章
- BZOJ5316 : [Jsoi2018]绝地反击
若$R=0$,那么显然答案为离原点最远的点到原点的距离. 否则若所有点都在原点,那么显然答案为$R$. 否则考虑二分答案$mid$,检查$mid$是否可行. 那么每个点根据对应圆交,可以覆盖圆上的一部 ...
- 洛谷P4518 [JSOI2018]绝地反击(计算几何+二分图+退流)
题面 传送门 题解 调了咱一个上午-- 首先考虑二分答案,那么每个点能够到达的范围是一个圆,这个圆与目标圆的交就是可行的区间,这个区间可以用极角来表示 首先,如果我们知道这个正\(n\)边形的转角,也 ...
- 【bzoj1822】[JSOI2010]Frozen Nova 冷冻波 计算几何+二分+网络流最大流
题目描述 WJJ喜欢“魔兽争霸”这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线 ...
- 【BZOJ3993】星际战争(网络流,二分答案)
[BZOJ3993]星际战争(网络流,二分答案) 题面 Description 3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战.在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团 ...
- 【BZOJ5251】【八省联考2018】劈配(网络流,二分答案)
[BZOJ5251][八省联考2018]劈配(网络流,二分答案) 题面 洛谷 BZOJ Description 一年一度的综艺节目<中国新代码>又开始了. Zayid从小就梦想成为一名程序 ...
- 【POJ】2318 TOYS ——计算几何+二分
TOYS Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10281 Accepted: 4924 Description ...
- 洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)
洛谷题目传送门 了解网络流和dinic算法请点这里(感谢SYCstudio) 题目 题目背景 这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你.(奶牛 ...
- 洛谷P4382 [八省联考2018]劈配(网络流,二分答案)
洛谷题目传送门 说不定比官方sol里的某理论最优算法还优秀一点? 所以\(n,m\)说不定可以出到\(1000\)? 无所谓啦,反正是个得分题.Orz良心出题人,暴力有70分2333 思路分析 正解的 ...
- LGP4518[JSOI2018]绝地反击
题解: 只要确定了每艘飞船的就位位置,就可以用二分+网络流求得答案: 定义偏转角度$a$为离$x$正半轴逆时针最近的边的弧度,$a \in [0,\frac{2\pi}{n})$ 二分一个值,对于一个 ...
随机推荐
- #Leetcode# 633. Sum of Square Numbers
https://leetcode.com/problems/sum-of-square-numbers/ Given a non-negative integer c, your task is to ...
- connect、resource和dba三种标准角色
授权语句:grant connect,resource,dba to zwserver 经过授权以后,用户拥有connect.resource和dba三个角色的权限: (1)Connect 角色,是授 ...
- Oracle通过ROWID删除表中重复记录
-- 1 通过ROWID删除T1表里重复的记录 SELECT ROWID,A,B--DELETE FROM T1WHERE ROWID IN ( SELECT RD FROM ( ...
- Redis 使用命令行的方式 获取 hash type key 的value值
1. 之前只是非常简单的看了下 get key 和 set key 但是这样 设置的 key value 应该是都 string 类型的 2. 但是没考虑过其他类型的 是如何获取 相关内容的 ,一直 ...
- PostgreSQL 安装了contrib 之后 登录失败的问题
1. 自己之前只是安装了 pg 10.6 2. 开发同事 需要用到 一个extensions 叫做 uuid-ossp 3. 执行报错 详情见昨天的blog 4. 然后执行了升级操作 结果 pg10 ...
- oninput和onchange的区别
菜鸟教程: oninput事件:HTML5标准事件 当用户向<input>中尝试输入时执行JavaScript: <input type="text" oninp ...
- mapreduce join
MapReduce Join 对两份数据data1和data2进行关键词连接是一个很通用的问题,如果数据量比较小,可以在内存中完成连接. 如果数据量比较大,在内存进行连接操会发生OOM.mapredu ...
- 在linux命令下访问url
1.elinks - lynx-like替代角色模式WWW的浏览器 例如: elinks --dump http://www.baidu.com 2.wget 这个会将访问的首页下载到本地 [root ...
- 《笔记》Python itertools的groupby分组数据处理
今天遇到这么一个需求,需要将这样的数据进行分组处理: [(, ), (, ), (, ), (, ), (, ), (, )] 处理之后我可能需要得到这样的结果: [(, (, , (, , (, ) ...
- 一、Dev
一.获取选中的表格 // MessageBox.Show(gridview_Parent.GetFocusedDataRow()["series"].ToString());//获 ...