LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流

时间:2022-09-07 14:25:35

题目:https://loj.ac/problem/2548

如果知道正多边形的顶点,就是二分答案、二分图匹配。于是写了个暴力枚举多边形顶点的,还很愚蠢地把第一个顶点枚举到 2*pi ,其实只要 \( \frac{2*pi}{n} \) 就行了。

总之能得10分。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define db double
using namespace std;
db Mx(db a,db b){return a>b?a:b;}
db Mn(db a,db b){return a<b?a:b;}
const int N=,M=N*N;
const db eps=1e-,Pls=1e-,pi2=*acos(-);
int dcmp(db x)
{ if(x>eps)return ;if(x<-eps)return -;return ;} int n,R; db dis[N][N];
int hd[N],xnt,to[M],nxt[M],per[N],dfn[N],tim;
struct Node{ db x,y;}a[N],b[N];
db Sqr(db x){return x*x;}
db get_dis(Node u,Node v)
{return sqrt(Sqr(u.x-v.x)+Sqr(u.y-v.y));}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
bool xyl(int cr)
{
for(int i=hd[cr],v;i;i=nxt[i])
if(dfn[v=to[i]]!=tim)
{
dfn[v]=tim;
if(!per[v]||xyl(per[v]))
{ per[v]=cr; return true;}
}
return false;
}
bool chk(db lm)
{
memset(hd,,sizeof hd); xnt=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(dcmp(dis[i][j]-lm)<=)add(i,j);//<= not <
memset(per,,sizeof per);memset(dfn,,sizeof dfn);//dfn!!
for(int i=;i<=n;i++)
{tim=i; if(!xyl(i))return false;}
return true;
}
int main()
{
scanf("%d%d",&n,&R);
for(int i=;i<=n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
db ans=;
for(db alp=;alp<=pi2;alp+=Pls)
{
db bs=*acos(-)/n;
for(int i=;i<=n;i++)
{
alp+=bs; if(alp>pi2)alp-=pi2;
b[i].x=R*cos(alp); b[i].y=R*sin(alp);
}
db l=,r=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
dis[i][j]=get_dis(a[i],b[j]),r=Mx(r,dis[i][j]);
r=Mn(r+eps,ans);
while(r-l>=eps)
{
db mid=(l+r)/;
if(chk(mid))ans=mid,r=mid-eps;
else l=mid+eps;
}
}
printf("%.8f\n",ans);
return ;
}

题解:https://www.cnblogs.com/cjyyb/p/10420259.html

首先,把二分放在外面,已知二分值,再考虑是否存在一个合法多边形。

已知二分值,一个点的可匹配范围是圆弧上一段区间。

合法方案可以转动多边形使得某个顶点卡在某个范围的边界上。一共有 O(n) 个边界,让多边形的第一个点分别卡上去即可。O( n4logn )。

多边形第一个点的转动角度可以对 \( \frac{2*pi}{n} \) 取模。

因为多边形两点在圆弧上的间距是 \( \frac{2*pi}{n} \) ,转动角度又小于 \( \frac{2*pi}{n} \) ,所以不管怎么转,对一个点的匹配最多导致一条边被删除/加入。

每个点产生两个转动角度,可知一个使得可以多匹配一个顶点,另一个使得少匹配一个顶点;角度取模后排序,每次把一个角度的影响加入后,整个图多/少了一条边。

删掉一条边 ( u , v ) 的话,看看它如果有流量,就手动给源点到 u 的边、 v 到汇点的边改一下流量。注意给总流量减 1 。

每次删/加边之后跑一次网络流即可。注意删边也要跑。

找一个点在圆弧上的区间,用余弦公式可知 R , mid , dis 围成的三角形的一个角的 cos 。

要特判一个点可以走到圆上任一点,还要特判走不到圆上的任一点。不然 acos( ) 会有 nan 。

代码里是把圆的 x 轴上的那个点看作第 n 个点。转动看作顺时针转动。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define db double
using namespace std;
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
db Sqr(db x){return x*x;}
const int N=,N2=N<<,M=N*N2;
const db jmp=1e-,eps=1e-,pi2=*acos(-);
int dcmp(db x)
{if(x>eps)return ;if(x<-eps)return -;return ;} int n,r2,nR,en; db x[N],y[N],alp[N],dis[N],d2[N],bs;
int hd[N2],cur[N2],xnt,to[M],nxt[M],cap[M],dfn[N2],q[N2];//N2
struct Node{
db x;int u,v;bool fx;
Node(db x=,int u=,int v=,bool f=):
x(x),u(u),v(v),fx(f) {}
bool operator< (const Node &b)const
{return x<b.x;}
}t[N<<];
void add(int x,int y)
{
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=;
}
void del(int x,int y,int &flow)
{
int tp=;
for(int i=hd[x],pr;i;pr=i,i=nxt[i])
if(to[i]==y)
{if(i==hd[x])hd[x]=nxt[i]; else nxt[pr]=nxt[i]; break;}
for(int i=hd[y],pr;i;pr=i,i=nxt[i])
if(to[i]==x)
{ if(i==hd[y])hd[y]=nxt[i]; else nxt[pr]=nxt[i];
tp=cap[i]; break;}
if(!tp)return; flow--;
for(int i=hd[x];i;i=nxt[i])
if(to[i]==){ cap[i]=;cap[i^]=;break;}
for(int i=hd[y];i;i=nxt[i])
if(to[i]==en){ cap[i]=;cap[i^]=;break;}
}
bool bfs()
{
int he=,tl=; memset(dfn,,sizeof dfn);
dfn[]=; q[++tl]=;
while(he<tl)
{
int k=q[++he];
for(int i=hd[k],v;i;i=nxt[i])
if(cap[i]&&!dfn[v=to[i]])
dfn[v]=dfn[k]+, q[++tl]=v;
}
return dfn[en];
}
int dinic(int cr,int flow)
{
if(cr==en)return flow;
int use=;
for(int &i=cur[cr],v;i;i=nxt[i])
if(cap[i]&&dfn[v=to[i]]==dfn[cr]+)
{
int tmp=dinic(v,Mn(flow-use,cap[i]));
if(!tmp)dfn[v]=;
use+=tmp; cap[i]-=tmp; cap[i^]+=tmp;
if(use==flow)return use;
}
return use;
}
bool chk(db mid)
{
xnt=;memset(hd,,sizeof hd); int tot=;
db m2=Sqr(mid);
for(int i=;i<=n;i++)
{
if(mid>=dis[i]+nR)
{ for(int j=;j<=n;j++)add(i,j+n); continue;}
if(mid<dis[i]-nR)continue;////
db fx=acos((r2+d2[i]-m2)/(*nR*dis[i]));
db l=alp[i]-fx, r=alp[i]+fx;
if(l<)l+=pi2; if(r<)r+=pi2;//r<0 for alp<0
int L=l/bs, R=r/bs;//bs not pi2
//if(!L)L=n; if(!R)R=n;//not for l-L*bs
t[++tot]=Node(l-L*bs,i,L?L:n,);//bs not pi2
t[++tot]=Node(r-R*bs,i,R?R:n,);
if(!L)L=n; if(!R)R=n;//
if(L<=R)
for(int j=L+;j<=R;j++)add(i,j+n);
else
{ for(int j=L+;j<=n;j++)add(i,j+n);
for(int j=;j<=R;j++)add(i,j+n);}
}
int flow=;
for(int i=;i<=n;i++)add(,i),add(i+n,en);
while(bfs())memcpy(cur,hd,sizeof hd),flow+=dinic(,n);
if(flow==n)return true;
sort(t+,t+tot+);
for(int i=;i<=tot;i++)
if(!t[i].fx)
{
add(t[i].u,t[i].v+n);
if(bfs())memcpy(cur,hd,sizeof hd),flow+=dinic(,n);
if(flow==n)return true;
}
else
{
del(t[i].u,t[i].v+n,flow);
if(bfs())memcpy(cur,hd,sizeof hd),flow+=dinic(,n);//
}
return false;
}
int main()
{
scanf("%d%d",&n,&nR); bs=pi2/n; en=(n<<)+; r2=Sqr(nR);
for(int i=;i<=n;i++)
{
scanf("%lf%lf",&x[i],&y[i]);
alp[i]=atan2(y[i],x[i]);
dis[i]=sqrt(Sqr(x[i])+Sqr(y[i]));
d2[i]=Sqr(dis[i]);
}
db l=,r=,ans;
while(r-l>jmp)
{
db mid=(l+r)/;
if(chk(mid))ans=mid,r=mid-jmp;
else l=mid+jmp;
}
printf("%.8f\n",ans);
return ;
}

LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流的更多相关文章

  1. 【LOJ】&num;2548&period; 「JSOI2018」绝地反击

    题解 卡常卡不动,我自闭了,特判交上去过了 事实上90pts= = 我们考虑二分长度,每个点能覆盖圆的是一段圆弧 然后问能不能匹配出一个正多边形来 考虑抖动多边形,多边形的一个端点一定和圆弧重合 如果 ...

  2. LOJ 2550 「JSOI2018」机器人——找规律&plus;DP

    题目:https://loj.ac/problem/2550 只会写20分的搜索…… #include<cstdio> #include<cstring> #include&l ...

  3. LOJ 2551 「JSOI2018」列队——主席树&plus;二分

    题目:https://loj.ac/problem/2551 答案是排序后依次走到 K ~ K+r-l . 想维护一个区间排序后的结果,使得可以在上面二分.求和:二分可以知道贡献是正还是负. 于是想用 ...

  4. LOJ 2547 「JSOI2018」防御网络——思路&plus;环DP

    题目:https://loj.ac/problem/2547 一条树边 cr->v 会被计算 ( n-siz[v] ) * siz[v] 次.一条环边会被计算几次呢?于是去写了斯坦纳树. #in ...

  5. LOJ 2546 「JSOI2018」潜入行动——树形DP

    题目:https://loj.ac/problem/2546 dp[ i ][ j ][ 0/1 ][ 0/1 ] 表示 i 子树,用 j 个点,是否用 i , i 是否被覆盖. 注意 s1<= ...

  6. loj&num;2574&period; 「TJOI2018」智力竞赛 &lpar;路径覆盖&rpar;

    目录 题目链接 题解 代码 题目链接 loj#2574. 「TJOI2018」智力竞赛 题解 就是求可重路径覆盖之后最大化剩余点的最小权值 二分答案后就是一个可重复路径覆盖 处理出可达点做二分图匹配就 ...

  7. Loj &num;3055&period; 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  8. Loj &num;3057&period; 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  9. LOJ &num;6436&period; 「PKUSC2018」神仙的游戏&lpar;字符串&plus;NTT&rpar;

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

随机推荐

  1. ASP&period;NET MVC5&plus;EF6&plus;EasyUI 后台管理系统(53)-工作流设计-我的批阅

    系列目录 前言:由于工作原因工作流一直没时间更新,虽然没有更新,但是批阅和申请差不多,改变一下数据的状态字段就行,有几个园友已经率先完成了 说句实话,一个工作流用文章表达很难,我起初以为这是一个很简单 ...

  2. hdu 1502 Regular Words

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=1502 思路:给定一个n,分别由n个a,b,c组成的字符串的所有前缀中a的个数大于等于b的个数大于等于c的个 ...

  3. CoreAnimation方法汇总

    使用CoreAnimation一般分为三个部分:1.创建执行动画的CALayer 2.创建动画 3.CALayer 添加Animation CoreAnimation是以锚点为基础. CoreAnim ...

  4. selenium Gird

    selenium-server selenium Gird testcase-----------------hub -------------------node1 ---------------- ...

  5. arguments&period;callee查询调用b函数的是哪个函数

    // function functionname(){ // function b(){ // console.log(arguments.callee.caller.name); // } // b ...

  6. 【解决办法】糟糕,我的电脑只有IE64位浏览器能上网,其他软件都上不了网

      最近两周在三班四班有5位同学电脑7次出现网络故障,表现为能连上锐捷.DNS正常却不能上网,其中在我自己的计算机上就发生了2次.上网搜集并整理了以下资料,供大家参考.请直接参见[解决办法]. [网上 ...

  7. &period;net core 2&period;x - 缓存的四种方式

    其实这些微软docs都有现成的,但是现在的人想对浮躁些,去看的不会太多,所以这里就再记录下 ,大家一起懒一起浮躁,呵呵. 0.基础知识 通过减少生成内容所需的工作,缓存可以显著提高应用的性能和可伸缩性 ...

  8. jQuery数字滚动(模拟网站人气、访问量递增)原创

    插件描述:实现数字上下滚动,模拟网站人气.访问量递增的动画效果,兼容性如下: 使用方法 $(el).runNum(val,params);   参数详解 val:数值型(默认70225800): pa ...

  9. &lbrack;环境配置&rsqb;Ubuntu 16&period;04 源码编译安装OpenCV-3&period;2&period;0&plus;OpenCV&lowbar;contrib-3&period;2&period;0及产生的问题

    1.OpenCV-3.2.0+OpenCV_contrib-3.2.0编译安装过程 1)下载官方要求的依赖包 GCC 4.4.x or later CMake 2.6 or higher Git GT ...

  10. Material Design系列第六篇——Defining Custom Animations

    Defining Custom Animations //自定义动画 This lesson teaches you to //本节课知识点 Customize Touch Feedback //1. ...