横坐标和纵坐标可以分开处理,就是区间上的贪心问题,贪心策略是按右端点从小到大排序,若右端点相同则按左端点从大到小排序,然后在区间上从左向右取点。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=5000+5;
typedef struct POINT{
int xl,yl,xr,yr;
int px,py;
int id;
}Point;
int view[maxn];
bool compare_x(Point p1,Point p2){
return p1.xr<p2.xr||((p1.xr==p2.xr)&&(p1.xl>p2.xl));
}
bool compare_y(Point p1,Point p2){
return p1.yr<p2.yr||((p1.yr==p2.yr)&&(p1.yl>p2.yl));
}
bool compare_id(Point p1,Point p2){
return p1.id<p2.id;
}
int n;
Point point[maxn];
int main(){
scanf("%d",&n);
while(n){
int j;
int flag=0;
for(int i=1;i<=n;i++){
scanf ("%d %d %d %d",&point[i].xl,&point[i].yl,&point[i].xr,&point[i].yr);
point[i].id=i;
}
//x 方向
memset(view,0,sizeof(int)*maxn);
sort(point+1,point+n+1,compare_x);
for (int i=1;i<=n;i++){
for (j=point[i].xl;j<=point[i].xr;j++){
if (!view[j]){//x可放
view[j]++;
point[i].px=j;
break;
}
}
if (j==point[i].xr+1) {
flag=1;//以失败
break;
}
}
//y方向
if(!flag){
memset(view,0,sizeof(int)*maxn);
sort(point+1,point+n+1,compare_y);
for (int i=1;i<=n;i++){
int y=point[i].yl;
for (j=point[i].yl;j<=point[i].yr;j++){
if (!view[j]){//y可放
view[j]++;
point[i].py=j;
break;
}
}
if (j==point[i].yr+1) {
flag=1;//以失败
break;
}
}
}
if(flag){
printf ("IMPOSSIBLE\n") ;
}
else {
sort(point+1,point+n+1,compare_id);
for (int i=1;i<=n;i++) {
printf ("%d %d\n",point[i].px,point[i].py);
}
}
scanf("%d",&n);
}
return 0;
}