从简单情形入手:
考虑只有一列,有n行,现在每个棋子的区域就是一个[le,ri],
那么问题就是在n个线段区域内的每个区域选一个点,使得1,2,3,...,n每个格子都被选中恰好一次。
不拿发现解法就是贪心,
再作进一步考虑:现在有n个区间,n行,n列,所有列都被选中了,现在考虑怎样使每一行都被选中且仅选中一次,
无论n个区间是怎样选择使得每一列都被选中,每一区间都必须选一个行,
也就是说满足每一列都被选中一次,与满足每一行都被选中一次是无关的。
原问题的 等价于 : n个区间,每个范围有两条线段[le,ri],[up,down],
在每个[le,ri]内选一个格子,使得列[1,n]每一列都被选中一次。区间i所选的列记为ans[i][0]。
在每个[up,down]内选一个格子,使得行[1,n]每一列都被选中一次。区间i所选的列记为ans[i][1]。
那么棋子i的位置就是[ans[i][0],ans[i][1]]。
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source£ºuva 11134
* @type: 问题分解
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 5000 ;
struct Node
{
int le,ri,ind;
bool operator<(const Node y)const
{
return ri>y.ri;
}
} a[maxn+4],b[maxn+4];
int n;
int ans[maxn+4][2];
bool cmp(Node x,Node y)
{
return x.le<y.le;
}
bool work(Node x[],int kind)
{
priority_queue<Node>q;
int pos=1;
for(int i=1;i<=n;i++)
{
while(!q.empty()&&q.top().ri<i)
{
q.pop();
}
while(pos<=n&&x[pos].le<=i)
{
q.push(x[pos++]);
}
if(q.empty()) return false;
Node tmp=q.top();q.pop();
int &ind=tmp.ind;
ans[ind][kind]=i;
}
return true;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].le,&b[i].le,&a[i].ri,&b[i].ri);
a[i].ind=b[i].ind=i;
}
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+n,cmp);
if(!work(a,0)||! work(b,1) )
{
puts("IMPOSSIBLE");
continue;
}
for(int i=1;i<=n;i++)
{
printf("%d %d\n",ans[i][0],ans[i][1]);
}
}
return 0;
}