「JSOI2018」绝地反击

「JSOI2018」绝地反击

传送门

Loj

题解

明显是二分答案.

首先考虑每一个点在一个时间内能够到达的点是一个圆,那么如果圆和大圆相离,显然不行.

现在考虑有交,你取的一定是两个端点中的一个,接着你就可以发现这个东西可以网络流.

唯一的问题在于,你需要考虑这段区间外要把这个匹配删除,那么可以考虑模拟退流的过程.

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<set>
#include<map>
using namespace std;
#define mp make_pair
#define ll long long
#define re register
typedef pair<int,int> pii;
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=5010,Inf = 1e9+10;
const double Pi=acos(-1.0),eps=1e-8;
int n,R,x[N],y[N],Q;
double nd;
struct node{int to,nxt,w;}e[N*N<<2];
struct ques{int u,v,opt;double ang;}q[N];
int front[N], cnt, s, t, dep[N] ;
void Add(int u,int v,int w)
{
	e[cnt]=(node){v,front[u],w};front[u]=cnt++;
	e[cnt]=(node){u,front[v],0};front[v]=cnt++;
}
bool cmp(ques a, ques b){return  a.ang == b.ang ? a.opt > b.opt : a.ang < b.ang;}
queue<int>Que;
bool bfs() 
{
	memset(dep, 0, sizeof(dep)); dep[s] = 1; Que.push(s);
	while(!Que.empty())
	{
		int u = Que.front(); Que.pop();
		for(int i = front[u]; ~i; i = e[i].nxt) 
		{          
			int v = e[i].to; 
			if(e[i].w && !dep[v])
			{
				dep[v] = dep[u] + 1;
				Que.push(v);
			}
		}
	}
	return dep[t];
}
int dfs(int u, int flow)
{
	if(u==t||!flow) return flow;
	for(int i=front[u];~i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(e[i].w&&dep[v]==dep[u]+1)
		{
			int di=dfs(v, min(flow, e[i].w));
			if(di){e[i].w-=di;e[i^1].w+=di;return di; }
			else dep[v] = -1;
		}
	}
	return 0;
}
void del(int u,int v,int &ans)
{
	int val=0;
	for(int j=0,i=front[v];i;j=i,i=e[i].nxt)
		if(e[i].to==u)
		{
			j?(e[j].nxt=e[i].nxt):(front[v]=e[i].nxt);
			break;
		}
	for(int j=0,i=front[u];i;j=i,i=e[i].nxt)
		if(e[i].to==v)
		{
			j?(e[j].nxt=e[i].nxt):(front[u]=e[i].nxt);val=e[i].w^1;
			break;
		}
	if(!val)return;--ans;
	for(int i=front[s];i;i=e[i].nxt)if(e[i].to==u){e[i].w^=1,e[i^1].w^=1;break;}
	for(int i=front[t];i;i=e[i].nxt)if(e[i].to==v){e[i].w^=1,e[i^1].w^=1;break;}
	if(bfs())ans+=dfs(s,Inf);
}
bool check(double mid)
{
	memset(front,-1,sizeof(front));cnt=0;Q=0;
	for(int i=1;i<=n;i++)Add(s,i,1),Add(i+n,t,1);
	for(int i=1;i<=n;i++)
	{
		double dis=sqrt(x[i]*x[i]+y[i]*y[i]);
		if(dis>mid+R||dis<R-mid)return false;
		if(dis+R<=mid)
		{
			for(int j=1;j<=n;j++)Add(i,j+n,1);
			continue;
		}
		double ang=atan2(y[i],x[i]),ex=acos((1.0*R*R+dis*dis-mid*mid)/(2*dis*R));
		double l=ang-ex,r=ang+ex;
		while(l<0)l+=2*Pi;while(r<0)r+=2*Pi;
		int L=l/nd,R=r/nd;
		q[++Q]=(ques){i,L+1,1,l-L*nd};
		q[++Q]=(ques){i,R+1,-1,r-R*nd};
		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);
		}
	}
	sort(q+1,q+Q+1,cmp);int ans = 0;
	while(bfs()) ans += dfs(s, Inf) ;
	if(ans==n)return true;
	for(int i = 1; i <= Q; 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 del(q[i].u, q[i].v + n ,ans );
	return false;
}
int main()
{
	n=gi();R=gi();nd=2.*Pi/n;s=0;t=n<<1|1;
	for(int i=1;i<=n;i++){x[i]=gi(),y[i]=gi();}
	double l=0,r=300;
	while(r-l>eps)
	{
		double mid=(l+r)/2;
		if(check(mid))r=mid;
		else l=mid;
	}
	printf("%.10lf\n",l);
	return 0;
}
posted @ 2020-06-01 22:12  fexuile  阅读(251)  评论(0编辑  收藏  举报