UVA 11134 Fabled Rooks

题意:在一个n*n的棋盘上放n个车,不互相攻击,每个车有自己放置的范围(一个矩形) 求放置方案

两个车不互相攻击的条件是既不在同一行也不在同一列 。而关键在于:行和列其实是无关的,可以分开单独处理。

现在问题变成一维的了,每个车有一个左右的区间,求放置方案。因为n个格子,n个车,每个格子都要放车,每个车也都要被放置。

那么对当前第i个格子,首先要知道有哪些车的可放置区间包含它,而这些车就是可选择的。

处理哪些车可选时,可以用结构体排序,按照区间左端点来排,这要枚举到格子i 时 把所以 l==i 的区间入列即可 

(而如果之前放进了的某个区间的r 小于i  还没被删除  那么这个车就没被放置 即无解了)

那么选哪个最优呢?

我们应该选择可选择的车中区间右端点最小的那个,因为右端点最小的那个最容易在i 向下一个移动时,就无法放置了。

所以我们可以再用一个优先队列来维护区间的右端点和编号 这样每次取出右端点最小的 如果已经小于当前i 就是无解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1000000007;
const int maxn=5000+10;
const int inf=1e9;
struct T
{
    int l,r,id;
    bool operator < (const T &b) const
    {
        if(l!=b.l)
            return l<b.l;
        return r<b.r;
    }
} x[maxn],y[maxn];
struct T2
{
    int x,y;
} ans[maxn];
priority_queue<pii,vector<pii>,greater<pii> > q;
int n;
bool go()
{
    int cnt=0;
    while(!q.empty())q.pop();
    for(int i=1; i<=n; i++)
    {
        while(cnt<n&&x[cnt].l<=i)
            q.push((pii){x[cnt].r,x[cnt].id}),cnt++;
        if(q.empty())return 0;
        pii now=q.top();
        q.pop();
        if(now.first<i) return 0;
        ans[now.second].x=i;
    }
    cnt=0;
    while(!q.empty())q.pop();
    for(int i=1; i<=n; i++)
    {
        while(cnt<n&&y[cnt].l<=i)
            q.push((pii){y[cnt].r,y[cnt].id}),cnt++;
        if(q.empty())return 0;
        pii now=q.top();
        q.pop();
        if(now.first<i) return 0;
        ans[now.second].y=i;
    }
    return 1;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0; i<n; i++)
        {
            x[i].id=y[i].id=i;
            scanf("%d%d%d%d",&x[i].l,&y[i].l,&x[i].r,&y[i].r);
        }
        sort(x,x+n);
        sort(y,y+n);
        if(go()){
            for(int i=0;i<n;i++)
            printf("%d %d\n",ans[i].x,ans[i].y);
        }
        else puts("IMPOSSIBLE");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值