UVA 11134 FabledRooks

摘要:贪心,问题分解。

因为行列无关,所以这个二维问题可以分解成两个一维问题。

第一种贪心:类似区间点覆盖的问题,先按照左端点排序,相同然后在按右端点排序(灵活性小的优先选)。最优的选法,当然是要使选的这个点经过的区间越少越好,那么就选最左边的点,因为选右边可能多经过区间,一定不比选最左边的更优。选完之后,就要把选过的区间忽略,并且把包含这个点的区间做修改,这个修改是动态的,所以可用一个优先对列来实现。

71ms

#include<bits/stdc++.h>
using namespace std;

const int maxn = 5003;
struct seg
{
    int l,r,id;
    seg(int L,int R) { l = L; r = R; }
    seg(){}
    bool operator < (const seg& rhs) const {
        return l > rhs.l || ( l == rhs.l && r > rhs.r);
    }
};

seg dim[2][maxn];
int rooks[maxn][2];

priority_queue<seg> q;

bool solve(int n,int d)
{
    for(int i = 0; i < n; i++){
       q.push(dim[d][i]);
    }
    int last = 0;
    int id = 0;
    while(q.size()){
        seg cur = q.top(); q.pop();
        if(cur.l>cur.r) return false;
        if(cur.l<=last) {
            cur.l = last + 1; q.push(cur);
        }else {
            last = cur.l;
            rooks[cur.id][d] = cur.l;
        }
    }
    return true;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    seg *R = dim[0], *C = dim[1];
    for(int i = 0; i < maxn; i++) dim[0][i].id = dim[1][i].id = i;
    while(~scanf("%d",&n)&&n){
        for(int i = 0; i < n; i++){
            scanf("%d%d%d%d",&R[i].l,&C[i].l,&R[i].r,&C[i].r);
        }
        if(solve(n,0)&&solve(n,1)){
             for(int i = 0; i < n; i++){
            printf("%d %d\n",rooks[i][0],rooks[i][1]);
            }
        }else puts("IMPOSSIBLE");

    }
    return 0;
}

优先队列

另外一种贪心,直接按照右端点排序,优先处理右端点最小的区间,因为它的灵活性最小。

但是我无法严格证明这种做法的正确性。。。如果哪位路过的大牛能证明这种做法的正确性就万分感谢了

这样做的效率要高一些

11ms

#include<bits/stdc++.h>
using namespace std;

const int maxn = 5003;
struct seg
{
    int l,r,id;
    bool operator < (const seg& rhs) const {
        return r < rhs.r ;
    }
};

seg dim[2][maxn];
int rooks[maxn][2];

bool solve(int n,int d)
{
    int last = -1;
    seg *Dim = dim[d];
    bool vis[n+1];
    memset(vis,0,sizeof(vis));
    sort(Dim,Dim+n);
    for(int i = 0; i < n; i++){
        int j;
        for(j = Dim[i].l; j <= Dim[i].r; j++) if(!vis[j]) {
                rooks[Dim[i].id][d] = j; vis[j] = true; break;
        }
        if(j>Dim[i].r) return false;
    }
    return true;
}

int main()
{
    int n;
    seg *R = dim[0], *C = dim[1];
    while(~scanf("%d",&n)&&n){
        for(int i = 0; i < n; i++){
            scanf("%d%d%d%d",&R[i].l,&C[i].l,&R[i].r,&C[i].r);
            R[i].id = C[i].id = i;
        }
        if(solve(n,0)&&solve(n,1)){
             for(int i = 0; i < n; i++){
            printf("%d %d\n",rooks[i][0],rooks[i][1]);
            }
        }else puts("IMPOSSIBLE");

    }
    return 0;
}

右端排序

时间: 2024-10-14 22:04:52

UVA 11134 FabledRooks的相关文章

(白书训练计划)UVa 11134 Fabled Rooks(贪心)

题目地址:UVa 11134 这题因为行与列是无关的,互无影响的.所以可以将行或列分开来计算.这就相当于转化成了在期间[1,n]内选择n个不同的整数,使得第i个整数在闭区间[Li,Ri]内.这就转换成了一个贪心问题了.但是注意不能先按照左端点排序,再按右端点排序,然后尽量往左边放,比如,(1,1),(1,3),(2,2),这样是不对的,应该按右端点为主关键字排序,再按左端点为次关键字排序.看到网上的方法全都是用每次选一个数后,都要在后面的区间中删去这个数,还要用到优先队列..感觉没必要这样做..

UVA - 11134 Fabled Rooks[贪心 问题分解]

UVA - 11134 Fabled Rooks We would like to place n rooks, 1 ≤ n ≤ 5000, on a n × n board subject to the following restrictions The i-th rook can only be placed within the rectan- gle given by its left-upper corner (xli,yli) and its right- lower corner

01_传说中的车(Fabled Rooks UVa 11134 贪心问题)

问题来源:刘汝佳<算法竞赛入门经典--训练指南> P81: 问题描述:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内. 问题分析:1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点.  2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序:每次在一个区间

uva 11134 - Fabled Rooks(主要在贪心方法及其实现)

#用到了贪心方法. #这个贪心刚开始想错了方法,后来想到了新的方法,AC 刚开始错在了按左端点升序排序并从左往右取最左端能取的格子,这个方法显然不能符合要求 比如下面这组数据: 2 1 1 3 3 1 1 3 3 2 2 2 2 错误代码: #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; struct note {

UVA 11134 Fabled Rooks 贪心

题目链接:UVA - 11134 题意描述:在一个n*n(1<=n<=5000)的棋盘上放置n个车,每个车都只能在给定的一个矩形里放置,使其n个车两两不在同一行和同一列,判断并给出解决方案. 算法分析:刚开始没有思路,后来看了别人的博客有了一点想法.我们把矩形的行和列分开解决,即n个车首先不能放置在同一行,然后判断n个车不能放置在同一列,如果都满足的话,即有正确的方法,否则就不行.那么怎样解决和判断在不在同一行并且是否可行呢,我们针对行而言,把这些行的坐标存入优先队列,首先取出最上面(行的标号

【uva 11134】Fabled Rooks(算法效率--问题分解+贪心)

题意:要求在一个N*N的棋盘上放N个车,使得它们所在的行和列均不同,而且分别处于第 i 个矩形中. 解法:问题分解+贪心. 由于行.列不相关,所以可以先把行和列均不同的问题分解为2个“在区间[1,n]中选择n个不同的整数,使得第 i 个整数在[Li,Ri]内”的问题. 接下来的贪心很重要:先使区间R从小到大排序,再L.这样在每个合法区间段中尽量往左边选数的情况下,就能保证每个区间的右边一段是灵活合法的,而若R1=R2,由于是从左开始填数,这并不影响.反正我是没有找到反例的......而不像我(

UVA 11134 Fabled Rooks

题意: 给你一个n*n的棋盘,让你在棋盘上放n个棋子,要求是所有棋子不能相互攻击(同行或者同列就会攻击),并且每个棋子都有一个限制,那就是必须在给定的矩形r[i]里,输出每个棋子的位置. 分析: 这个题看的是别人的题解.然后我们从前往后贪心,右端点越小的“自由性”越小,所以要先处理,所以放在前面,对于每一断,我们就从这个段的做端点开始找,找第一个没被占用的点,占用上就行了,如果都找到右端点了还没找到可以用的点,那么就直接没解了,x和y都是这么处理的. 代码: #include <iostream

Uva 11134 Fabled Rooks (问题分解 + 贪心放置)

题意: 给你n*n的棋盘,让放置n个车 使他们之间并不能相互攻击 附加条件是 给定n个车的放置区间 用左上角和右下角的坐标来表示 解题思路: 首先明确 横向的约束和纵向的约束其实并不互相影响 所以可以对横向和纵向单独求解 把问题变成两个一维的区间选点问题来求解 另外 在取点的时候 有贪心的思路在里面 对于n个区间 应该先选择区间中r最小的区间进行放置可放置的点 可以简单认为这是因为r越小的区间 其选择的灵活性就越低. 我刚开始的时候 是采取了先放置区间长度小的 在放置l小的区间 不正确. cod

UVa 11134 传说中的车

https://vjudge.net/problem/UVA-11134 题意:在n*n的棋盘上放n个车,使得任意两个车不相互攻击,且第i个车在一个给定的矩形Ri之内.用4个整数xli,yli,xri,yri来描述第i个矩形. 思路:行和列是不影响的,也就是说第i个棋子放在第几行不会影响它的列数.这样的话我们就可以分别处理行和列.由于棋子被给定了范围,这样的话我们可以用贪心法来解决,按照ri右坐标从小到大排序,然后从左坐标开始选出最小的且未被占据的坐标. 1 #include<iostream>