【BZOJ1822】【JSOI2010】Frozen Nova 冷冻波

14 篇文章 0 订阅
10 篇文章 0 订阅

题解:二分答案,然后网络流check。


注意:

理论上来讲,因为如果有 

                          -----------

                        /             \

                      /                \

巫妖----小精灵----------------树桩-------

                     \                  /

                      \                /

                        \----------- /

这种情况,直接用点到直线距离公式是会错误判断的。

但是读者们请用点到直线距离公式吧。

因为数据貌似是这样的。


不妨把巫妖的目光看成能穿透小精灵吧~(至于能反向发射,不妨想想:地球是圆的!光经过折射自然就可以理解成直线了)



贴个WA了的代码吧:

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 600
#define M 1001000
#define inf 10001000
#define eps 1e-5
using namespace std;
struct KSD
{
	int v,len,next;
}e[M];
int head[N],cnt,rl[M];
void add(int u,int v,int len)
{
	cnt++;
	e[cnt].v=v;
	e[cnt].len=rl[cnt]=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int s,t,d[N],maxflow;
int n,m,p;
struct Point
{
	int x,y,r,t;
}ksd[N],ashe[N],garen[N];
bool bfs()
{
	queue<int>q;
	int i,u,v;
	memset(d,0,sizeof(d));
	q.push(s);
	d[s]=1;
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(d[v]||e[i].len==0)continue;
			d[v]=d[u]+1;
			if(v==t)return 1;
			q.push(v);
		}
	}
	return 0;
}
int dinic(int x,int flow)
{
	if(x==t)return flow;
	int remain=flow,i,v,k;
	for(i=head[x];i&&remain;i=e[i].next)
	{
		if(d[v=e[i].v]==d[x]+1&&e[i].len)
		{
			k=dinic(v,min(remain,e[i].len));
			if(!k)d[v]=0;
			e[i].len-=k,e[i^1].len+=k;
			remain-=k;
		}
	}
	return flow-remain;
}
bool check(int mid)
{
	int i,j,k;
	maxflow=0;
	for(i=2;i<=cnt;i++)e[i].len=rl[i];
	for(i=1;i<=n;i++)e[i<<1].len=mid/ksd[i].t+1;
	while(bfs())maxflow+=dinic(s,inf);
	if(maxflow==m)return 1;
	else return 0;
}
void build()
{
	int i,j,k;
	double K,B,D,tx,ty;
	scanf("%d%d%d",&n,&m,&p);
	s=n+m+1,t=n+m+2,cnt=1;
	for(i=1;i<=n;i++)scanf("%d%d%d%d",&ksd[i].x,&ksd[i].y,&ksd[i].r,&ksd[i].t),add(s,i,1),add(i,s,0);
	for(i=1;i<=m;i++)scanf("%d%d",&ashe[i].x,&ashe[i].y),add(i+n,t,1),add(t,i+n,0);
	for(i=1;i<=p;i++)scanf("%d%d%d",&garen[i].x,&garen[i].y,&garen[i].r);
	
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			tx=ashe[j].x-ksd[i].x,ty=ashe[j].y-ksd[i].y;
			if(tx*tx+ty*ty>ksd[i].r*ksd[i].r)continue;// ashe在ksd施法范围外
			if(tx>0+eps||tx<0-eps)
			{
				K=-ty/tx;
				B=-K*ksd[i].x-ksd[i].y;
				for(k=1;k<=p;k++)
				{
					D=fabs((K*garen[k].x+garen[k].y+B)/sqrt(K*K+1));
					if(D-eps<=garen[k].r)break;
				}
			}
			else 
			{
				for(k=1;k<=p;k++)
				{
					D=fabs(garen[k].x-ksd[i].x);
					if(D-eps<=garen[k].r)break;
				}
			}
			if(k>p)add(i,j+n,1),add(j+n,i,0);
		}
	}
}
int main()
{
//	freopen("test.in","r",stdin);
//	freopen("my.out","w",stdout);
	int i,j,k;
	build();
	int l = 0,r = inf,ans = -1;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(check(mid))
			r = mid - 1,ans = mid;
		else	l = mid + 1;
	}
	/*for(i=1;i<=30&&l<=r;i++)
	{
		mid=l+r>>1;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}*/
	printf("%d\n",ans);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值