LIGHTOJ 1383 Underwater Snipers 二分好题+贪心区间覆盖

题目链接:http://lightoj.com/volume_showproblem.php?problem=1383

1383 - Underwater Snipers
Time Limit: 4 second(s)Memory Limit: 32 MB

King Motashota is in a war against the mighty Bachchaloks. He has formed a well trained army of snipers, and planning to use them as much as possible. In one of the missions, he has S snipers. They will be dispatched to get rid of the soldiers guarding the bank of the river Nodi.

From satellite images, Motashota has located positions of all enemy soldiers. Now, the plan is, snipers will take their positions. They are excellent swimmers, so, you can assume that they won't get caught, while taking position. Upon order from Motashota, they will start shooting enemy soldiers. A sniper can shoot a soldier, if Euclidean Distance between the soldier and sniper is no more than D. After the snipers get rid of all the soldiers, they can proceed with the operation. So, it is important for them to position the snipers in such a way that, all soldiers are within the range of at least one sniper.

In addition, when snipers start shooting, the guards will be alert, and thus, snipers can't change their position, they can only continue shooting from their position.

The river bank is defined by the horizontal line y = k. All points (x, y) where y > k is in the enemy territory, and if y < k, then it's on the water. You will be given location of N soldiers, strictly in the enemy territory; you have to place S soldiers in the water, so that they can kill all soldiers. For security reasons, the snipers should be as far from the bank as possible. For any sniper in position (xi, yi), the distance from the bank is |yi - k|. If, for all snipers, the minimum of them is M = min{|yi - k|}, you have to maximize M.

Both the soldiers and snipers are really superstitious. They will stay only in integer coordinates.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a black line. Next line contains four integers, k (-108 ≤ k ≤ 108), N (1 ≤ N ≤ 10000), S (1 ≤ S ≤ 10000) and D (1 ≤ D ≤ 109), the position of the bank, number of guards and number of snipers, and the range of the snipers.

This is followed by N lines, each containing a pair of integers (xi, yi) the position of ith guard (-108 ≤ xi ≤ 108, k < yi ≤ 108).

Output

For each case, print the case number and M which is described in the statement. If the snipers cannot kill all the guards, print "impossible".

Sample Input

Output for Sample Input

2

 

0 3 2 4

1 1

3 2

9 1

 

0 3 1 4

1 1

3 2

9 1

Case 1: 2

Case 2: impossible










又是一道好题,
题意:   y=k代表河岸,河岸上侧有n个敌人,在河岸下侧布置s个狙击手,狙击手射程为D,要求每个敌人至少被一个狙击手攻击到。

接下来的n行给出敌人的坐标,所有狙击手距离河岸的最小距离为M,求M的最大值。

题解:又是一最大化最小值,我们二分每一个M,那个就可以求出要打到每个敌人的最大坐标和最小坐标,这样就转化为一个最小区间覆盖问题,用贪心求解即可,确实比较吊的一道题。,

/**
 * @author neko01
 */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0);
const double eqs=1e-10;
struct point{
    LL x,y;
}a[10001],f[10001];
LL k,n,s,d;
bool cmp(struct point w,struct point v)
{
    return w.y<v.y;
}
bool gao(int mid)
{
    for(int i=0;i<n;i++)
    {
        if(mid+a[i].y>d)
            return false;
        LL t=(LL)sqrt(d*d*1.0-(mid+a[i].y)*(mid+a[i].y)*1.0);
        f[i].x=a[i].x-t,f[i].y=a[i].x+t;
    }
    sort(f,f+n,cmp);
    LL ans=0;
    int k=1;
    for(int i=0;i<n;i++)
    {
        ans++;
        if(ans>s)
            return false;
        while(f[i].y>=f[k].x)
        {
            k++;
            if(k>=n)
                break;
        }
        i=k-1;
    }
    if(ans>s)
        return false;
    return true;
}
int main()
{
    int T,cnt=0;
    scanf("%d",&T);
    while(T--)
    {
        LL ans=0;
        int flag=0;
        scanf("%lld%lld%lld%lld",&k,&n,&s,&d);
        for(int i=0;i<n;i++)
        {
            scanf("%lld%lld",&a[i].x,&a[i].y);
            a[i].y-=k;
        }
        LL l=0,r=d;
        while(l<=r)
        {
            LL mid=(l+r)>>1;
            if(gao(mid))
            {
                flag=1;
                ans=mid;
                l=mid+1;
            }
            else
                r=mid-1;
        }
        printf("Case %d: ",++cnt);
        if(!flag)
            printf("impossible\n");
        else
            printf("%lld\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值