[Uva11134]Fabled Rooks

Problem###

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 rectangle given by its left-upper corner (xli, yli) and its rightlower corner (xri, yri), where 1 ≤ i ≤ n, 1 ≤ xli ≤ xri ≤ n, 1 ≤ yli ≤ yri ≤ n.
• No two rooks can attack each other, that is no two rooks can occupy the same column or the same row.

Input###

The input consists of several test cases. The first line of each of them contains one integer number, n, the side of the board. n lines follow giving the rectangles where the rooks can be placed as described above. The i-th line among them gives xli, yli, xri, and yri. The input file is terminated with the integer ‘0’ on a line by itself.

Output###

Your task is to find such a placing of rooks that the above conditions are satisfied and then output n
lines each giving the position of a rook in order in which their rectangles appeared in the input. If there
are multiple solutions, any one will do. Output ‘IMPOSSIBLE’ if there is no such placing of the rooks.

Sample Input###

8
1 1 2 2
5 7 8 8
2 2 5 5
2 2 5 5
6 3 8 6
6 3 8 5
6 3 8 8
3 6 7 8
8
1 1 2 2
5 7 8 8
2 2 5 5
2 2 5 5
6 3 8 6
6 3 8 5
6 3 8 8
3 6 7 8
0

Sample Output###

1 1
5 8
2 4
4 2
7 3
8 5
6 6
3 7
1 1
5 8
2 4
4 2
7 3
8 5
6 6
3 7


题意##

在n( imes)n的棋盘上放n个车,要求车之间不能互相攻击(即没有2个车在同行或同列)。
每个车的放置范围为一个矩形,求这n个车的合理放置方法。


想法##

满足要求首先需要每行只有一个车,每列只有一个车
很容易看出来,行与列没有关系,可以各自单独考虑。

问题转化为,有n个位置,n个车,每个车可放置的位置为[l,r],求一种放置方案使每个位置都放上车
乍看上去有点难搞,考虑能不能贪心。

贪心算法一###

我们可以发现,如果有的位置只有一个车可放,或一个车只能放一个位置,那么这个位置必须放这个车
那么按车可放的范围从小到大排个序后考虑
将当前考虑的车找一个可放的 可放车数量最少 的位置放,将可放该位置的其他车标记不能放该位置
需要各种优先队列和数组,正确性不能证明。

贪心算法二###

想一想能发现,满足要求的放置方法应该不少。
类似区间规划问题,将车可放的范围以右端点从小到大排个序考虑
每个车放在可放的最靠左的位置。


正确性(不会有解却认为无解)证明##

对于每一个车,将其放置在可放的最靠左位置
若某一车没有位置可放,说明它的放置区间[l,r]中全放上了车
而当前放了车的全是右端点(leq)r的,往右挪挪不动,且任意车也都不能再往左挪
所以一定无解


代码##

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 5001;

struct data{
    int num,x1,x2,y1,y2;      
}a[N];
int pos[N],ansx[N],ansy[N];

bool cmp1(data a,data b) { return a.x2<b.x2 || (a.x2==b.x2 && a.x1<b.x1); }
bool cmp2(data a,data b) { return a.y2<b.y2 || (a.y2==b.y2 && a.y1<b.y1); }

int main()
{
    int n,flag;
    while(scanf("%d",&n) && n){
        for(int i=0;i<n;i++) {
            scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
            a[i].num=i;
        }
        sort(a,a+n,cmp1);
        memset(pos,0,sizeof(pos));
        flag=1;
        for(int i=0;i<n;i++){
            int j=a[i].x1;
            while(j<=a[i].x2 && pos[j]) 
                j++;
            if(j>a[i].x2) { flag=0; break; }
            pos[j]=1;
            ansx[a[i].num]=j;
        }
        sort(a,a+n,cmp2);
        memset(pos,0,sizeof(pos));
        for(int i=0;i<n;i++){
            int j=a[i].y1;
            while(j<=a[i].y2 && pos[j]) 
                j++;
            if(j>a[i].y2) { flag=0; break; }
            pos[j]=1;
            ansy[a[i].num]=j;
        }
        if(!flag) printf("IMPOSSIBLE
");
        else {
            for(int i=0;i<n;i++)
                printf("%d %d
",ansx[i],ansy[i]);     
        }
    }
    
    return 0;    
}

延伸题##

有n个格子,n个颜色不同的小球。将小球放入格子中。第i个小球可放在第[(l_i),(r_i)]的格子里。问n个格子中都放上小球的不同方案数。

既然选择了远方,便只顾风雨兼程
原文地址:https://www.cnblogs.com/lindalee/p/8343637.html