11134 - Fabled Rooks

因为行和列是无关的,所以可以单独处理,将问题分解成两个,那么需要求的就是在这n个区间里任选一个数,且这个数不重复。 这很像之前紫书上将的区间问题,可以采取贪心的策略,将区间(a,b) 先按照b从小到大排,再按照a从小到大排,然后在区间中的还没有被选的数字里优先挑选较小的数字。

但是由于这样经过排序后原来的顺序已经打乱了,所以预先给每个区间分配一个id ,一个v保存选的值,然后再按照id还原顺序就好了。

#include<bits/stdc++.h>
using namespace std;
const int max_n = 5005;
int n,vis_x[max_n],vis_y[max_n],vis[max_n];
struct point_x{
    int x1,x2,id,v;
}a[max_n];
struct point_y{
    int y1,y2,id,v;
}b[max_n];
bool cmp(point_x a,point_x b){
    return a.x2<b.x2||a.x2==b.x2&&a.x1<b.x1;
}
bool cmp2(point_y a,point_y b){
    return a.y2<b.y2||a.y2==b.y2&&a.y1<b.y1;
}
bool cmp3(point_x a,point_x b){
    return a.id<b.id;
}
bool cmp4(point_y a,point_y b) {
    return a.id<b.id;
}
int main(){
    while(~scanf("%d",&n)&&n){
        bool ok = true;
        for(int i=0;i<n;i++) {
            scanf("%d%d%d%d",&a[i].x1,&b[i].y1,&a[i].x2,&b[i].y2);
            a[i].id = b[i].id = i+1;
        }
        sort(a,a+n,cmp);
        memset(vis,0,sizeof(vis));
        int cnt = 0;
        for(int i=0;i<n;i++) {
            bool flage = true;
            for(int j=a[i].x1;j<=a[i].x2;j++){
                if(!vis[j]) {
                    vis[j] = 1; a[i].v = j; break;
                }
                if(j==a[i].x2) flage = false;
            }
            if(!flage) { ok = false; break; }
        }
        sort(b,b+n,cmp2);
        memset(vis,0,sizeof(vis));
        cnt = 0;
        for(int i=0;i<n;i++) {
            bool flage = true;
            for(int j=b[i].y1;j<=b[i].y2;j++){
                if(!vis[j]) {
                    vis[j] = 1; b[i].v = j; break;
                }
                if(j==b[i].y2) flage = false;
            }
            if(!flage) { ok = false; break; }
        }
        if(ok) {
            sort(a,a+n,cmp3);
            sort(b,b+n,cmp4);
            for(int i=0;i<n;i++){
                printf("%d %d\n",a[i].v,b[i].v);
            }
        } else printf("IMPOSSIBLE\n");
    }
    return 0;
}


你可能感兴趣的:(ACM,uva)