您的位置:首页 > 其它

C - Underwater Snipers UVALive - 5000 最小值最大化问题 二分

2017-04-01 17:58 309 查看
题目链接

题意:一条河岸线y=k,y>k区域有n个敌人,现在要在y<=k区域布置S个狙击手,狙击手的狙击范围为距离自己半径为D的圆内,问满足能够狙死所有的敌人的情况下,离河岸线最近的那个狙击手的离河岸线的最大距离是多少。

解法:求最小值最大的问题。二分这个距离,如果距离为x,那么最好是狙击手都站到y=k-x处,可以最大范围地打到敌人。

然后check的时候求出每个敌人在y=k-x线上的能够打到他的狙击手范围,为[Xi-sqrt(D^2-(Yi-k+x)*(Yi-k+x),Xi+sqrt(D^2-(Yi-k+x)*(Yi-k+x)],

然后就变成了区间选点问题,将所有的范围按右端点排序,扫一遍判断这么多区间需要布置多少个狙击手,最后如果需要的>S,那么check失败,否则成功。

   
有一个需要注意的问题是,我以前做过类似的题目,贪心取点的题目...这个题和那个题有所不同,这个题对区间排序的时候我们需要直接根据区间右端点从小到大排序,不能按照左端点升序排序,如果相等在按照右端点升序排序,因为遇到区间套区间的那种情况会出错.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node
{
ll x1;
ll x2;
}q[maxn];
ll k,n,s,d;
ll x[maxn],y[maxn];
bool cmp(node a,node b)
{
return a.x2<b.x2;
}
int check(ll m)
{
for(int i=1;i<=n;i++)
{
if(d*d-(y[i]-k+m)*(y[i]-k+m)<0)
return 0;
q[i].x1=x[i]-(ll)sqrt(d*d-(y[i]-k+m)*(y[i]-k+m));
q[i].x2=x[i]+(ll)sqrt(d*d-(y[i]-k+m)*(y[i]-k+m));//坑啊...
}
sort(q+1,q+1+n,cmp);
ll ss=q[1].x2;
ll cou=1;
for(int i=2;i<=n;i++)
{
if(q[i].x1>ss)
{
cou++;
ss=q[i].x2;
}
}
if(cou>s)
return 0;
else
return 1;
}
int main()
{
int t;
int tt=1;
scanf("%d",&t);
while(t--)
{
scanf("%lld %lld %lld %lld",&k,&n,&s,&d);
for(int i=1;i<=n;i++)
scanf("%lld %lld",&x[i],&y[i]);
ll l=0,r=d,mid,ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid)==0)
{
r=mid-1;
}
else
{
l=mid+1;
ans=mid;
}
}
printf("Case %d: ",tt++);
if(r<0)
printf("IMPOSSIBLE\n");
else
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: