自己一开始想的是如果中间的任意一颗棋子[1,n] 该怎么选择位置,根据多个区间的话,这也想下去的确好像有办法,把各个区间想重叠的地方 记录下来,则如果某个地方只有1次覆盖,则那个地方的数字只能由那个区间提供。
但是这样也比较麻烦,参考了别人的代码后才发现 如果你仅仅从最左边开始,这样就只需要考虑其右边一边了(如果你一开始就想放中间的话,要考虑左右两边的问题),这样的话再只考虑一边的情况下,肯定是选择当前区间更小的棋子,比如两个区间1,3和1,5。我们想在位置1放一颗棋子的时候肯定选择第一个区间,应该第二区间大了(要想清楚为什么大了不好),这样选好位置1的棋子后,又开始从位置2开始,这是因为位置1已经选好了,位置2从而也就只考虑右边一边的情况了。
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
//#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
bool solve(int*a,int*b,int*c,int n)//解决一维的问题:找一个c,使得a[i]<=c[i]<=b[i]
{
fill(c,c+n,-1);
for(int col=1;col<=n;col++)
{
int rook=-1,minb=n+1;
for(int i=0;i<n;i++)
if(c[i]<0&&b[i]<minb&&col>=a[i])//找一个没有安排过的车,它的b[i]最小
{
rook=i;minb=b[i];
}
if(rook<0||col>minb)return false; //如果没有找到,或者虽然找到了,但是最大范围小于col,则无解
c[rook]=col;
}
return true;
}
const int N=5000+5;
int n,x1[N],y1[N],x2[N],y2[N],x[N],y[N];
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
if(solve(x1,x2,x,n)&&solve(y1,y2,y,n))//两个一维的问题都解决了,那么本题就有解
for(int i=0;i<n;i++)
printf("%d %d\n",x[i],y[i]);
else puts("IMPOSSIBLE");
}
}