POJ 1328 3190 贪心 优先队列

8 篇文章 0 订阅
7 篇文章 0 订阅

微软题目没思路。。。。再推推吧。。。

POJ 1328

二维的区间覆盖,雷达固定在x轴上,问最少雷达数观测到所有小岛

最开始想着直接按照x轴或者y轴排序贪心,但是发现并不能,很容易就能找到反例,单单按照一个轴的方向排序并不能满足最优性。

考虑把一个点转化为一个区间,这个区间代表需要覆盖到这个点雷达可放置区间

其实和2376差不多,类似这种某个东西覆盖一些点的题目都是把数据转化为轴上可行的区间再操作。

转化为区间之后,将区间按l第一关键字从小到大,r第二关键字从大到小排序,每次判断当前区间和前一个区间是否有重叠。如果有重叠,就把当前区间更新为重叠部分。如果当前区间和前一个区间没有重叠,ans+1。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define Maxn 1000
using namespace std;

struct Interval {
    double x, y;
}inter[Maxn + 10];

int n, d, ans, tot, cnt;

bool cmp(Interval, Interval);

int main() {
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    while (scanf("%d%d", &n, &d), !(n == 0 && d == 0)) {
        cnt = 0;
        ans = 0;
        for (int i = 1;i <= n;++ i) {
            int tempx, tempy;
            scanf("%d%d", &tempx, &tempy);
            if (tempy > d)
                ans = -1;
            if (tempy >= 0) {
                double temp = sqrt(d * d * 1.0 - tempy * tempy * 1.0);
                inter[++ cnt].x = tempx - temp;
                inter[cnt].y = tempx + temp;
            }
        }
        if (ans == -1) {
            printf("Case %d: %d\n", ++ tot, ans);
            continue;
        }
        double nowx, nowy;
        sort(inter + 1, inter + 1 + cnt, cmp);
        for (int i = 1;i <= cnt;++ i) {
            if (ans == 0 || inter[i].x > inter[i - 1].y)
                ++ ans;
            else {
                inter[i].x = max(inter[i].x, inter[i - 1].x);
                inter[i].y = min(inter[i].y, inter[i - 1].y);
            }
        }
        /*for (int i = 1;i <= cnt;++ i)
            printf ("\n%.4lf %.4lf", inter[i].x, inter[i].y);*/
        printf("Case %d: %d\n", ++ tot, ans);
    }
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

bool cmp(Interval a, Interval b) {
    if (a.x != b.x)
        return a.x < b.x;
    return a.y > b.y;
}

POJ 3190

一如既往的cow风

n个牛要在一个位置上独自榨奶时间L到R,问至少需要多少榨奶位以及每个牛在哪个榨奶位。

先按照起始时间从小到大排序。再维护一个小根堆(或者说优先队列)保存当前建立的榨奶位,该榨奶位当前已被占用到lasttime作为关键字。每次对于当前牛,如果优先队列中top元素的lasttime小于当前牛的起始时间,那么当前牛可以直接被分配到这个榨奶位,再把lastime更新为当前牛的结束时间;如果top元素的lastime都大于当前牛的起始时间,那么需要新建一个榨奶位。每次维护优先队列的同时记录当前牛被分配到的榨奶位序号。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <functional>
#include <queue>
#define Maxn 50000
using namespace std;
2zsw
struct Interval {
    int l, r, num;
}inter[Maxn + 10];

struct Stall {
    friend bool operator < (Stall x, Stall y) {
        return x.last > y.last;
    }
    int num, last;
};

int n, ans;
int stall[Maxn + 10];

bool cmp(Interval, Interval);

int main() {
    scanf("%d", &n);
    for (int i = 1;i <= n;++ i) {
        scanf("%d%d", &inter[i].l, &inter[i].r);
        inter[i].num = i;
    }
    sort(inter + 1, inter + 1 + n, cmp);
    /*for (int i = 1;i <= n;++ i)
        printf("%d %d\n", inter[i].l, inter[i].r);*/
    priority_queue<Stall> que;
    for (int i = 1;i <= n;++ i) {
        if (ans == 0) {
            stall[inter[i].num] = ++ ans;
            Stall temp = {ans, inter[i].r};
            que.push(temp);
            //printf("Inter %d go to new stall %d\n", inter[i].num, ans);
            //printf("top stall last:%d\n", que.top().last);
            continue;
        }
        Stall temp = que.top();
        if (temp.last < inter[i].l) {
            que.pop();
            temp.last = inter[i].r;
            stall[inter[i].num] = temp.num;
            que.push(temp);
            //printf("Inter %d go to existed stall %d\n", inter[i].num, temp.num);
        }
        else {
            Stall tt = {++ ans, inter[i].r};
            stall[inter[i].num] = ans;
            que.push(tt);
            //printf("Inter %d go to new stall %d\n", inter[i].num, ans);
        }
        //printf("top stall last:%d\n", que.top().last);
    }
    printf("%d\n", ans);
    for(int i = 1;i <= n;++ i)
        printf("%d\n", stall[i]);
    return 0;
}

bool cmp(Interval a, Interval b) {
    return a.l < b.l;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值