UVA 11134 Fabled Rocks [贪心,但与一般题有些不同]

题目链接

容易发现,行与列是相互独立的,可以单独考虑 。 

看到白书上提示说是经典问题的变形,还以为是八皇后之类的,于是写了个回溯,果然TLE了。

仔细考虑后,可以对所有的区间[L,R]按某个顺序排好后,直接将1,2.....n填入每个区间即可。

怎样去排序呢,可能想到L小的要排前,L相同按R小的排前,因为将最小的数字填入 排好序后的第一个区间 不会使结果变糟。 可是这种贪心策略是正确的吗? 很可惜,这种做法不够严谨。 如:

[1 , 1]   [1 , 5]  [2 , 2]  [4 , 4 ] [5 , 5] 这个排序时错误的,正确的是[1 , 1]   [2 , 2]  [1 , 5]  [4 , 4 ] [5 , 5] 

前面的推导出了什么问题呢? 只能保证填入的第一个数是正确的。

怎么改正呢,填入第一个数后,将该区间[1 ,1 ]删除 ,将[1 , 5]改为[2 , 5] (因为现在1已经没有作用了),按相同策略重复上面过程即可。

注意 区间的顺序可以用优先队列来维护,不用每次都排一次序。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=5050;

struct Range{
    int l,r,id;
    bool operator < (const Range &b) const {
        return (l>b.l || (l==b.l && r>b.r));
    }
}xran[maxn],yran[maxn];
int n,ans[maxn][2];
bool check(Range* range , int type){
    priority_queue<Range>Q;
    for(int i=0;i<n;i++) Q.push(range[i]);
    int now = 1;
    while(!Q.empty()){
        Range tmp = Q.top(); Q.pop();
        if(tmp.r < now || tmp.l > now) return false;
        if(tmp.l < now) {
            tmp.l = now , Q.push(tmp);
            continue;
        }
        ans[tmp.id][type] = now++;
    }
    return true;
}
int main(){ 
    while(scanf("%d",&n)!=EOF && n){
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&xran[i].l,&yran[i].l,&xran[i].r,&yran[i].r);
            xran[i].id = yran[i].id = i;
        }
        if(check(xran,0) && check(yran,1)) {
            for(int i=0;i<n;i++){
                printf("%d %d\n",ans[i][0],ans[i][1]);
            }
        }
        else {
            puts("IMPOSSIBLE");
        }
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值