非常关键的一点是行和列是独立的,不相互影响。所以判断车是否相互攻击只需要行不相互攻击,列也不相互攻击即可。这样二维可以转化成两个一维。
一维的问题是,在给定的每个区间上选一个点使得该点不再其他区间上出现。贪心,优先给右端点小的线段选点即可。类似于上一个题,我用优先队列做得。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <algorithm> #define ll long long #define INF 2139062143 #define MOD 20071027 #define MAXN 20005 using namespace std; struct Segment { int l,r; int num,pos; Segment(int a=0,int b=0,int c=0):l(a),r(b),num(c) {} bool operator < (const Segment &p ) const { return r>p.r; } }; bool cmp(Segment a,Segment b) { return a.num<b.num; } vector<Segment> x[5005],y[5005]; void Init() { for(int i=1; i<=5000; ++i) { x[i].clear(); y[i].clear(); } } void process(priority_queue<Segment> &pq,int v,vector<Segment> &ans) { if(!pq.empty()) { Segment s=pq.top(); pq.pop(); s.pos=v; ans.push_back(s); } } bool solve(vector<Segment> vec[],vector<Segment> &ans,int minn,int maxn) { priority_queue<Segment> pq; for(int i=minn; i<=maxn; ++i) { if(!pq.empty()&&pq.top().r<i) return false; for(int j=0; j<vec[i].size(); ++j) pq.push(vec[i][j]); process(pq,i,ans); } if(pq.empty()) return true; else return false; } int main() { int n; while(scanf("%d",&n)&&n) { Init(); int a,b,c,d; int minx=INF,miny=INF,maxx=0,maxy=0; for(int i=0; i<n; ++i) { scanf("%d%d%d%d",&a,&b,&c,&d); x[a].push_back(Segment(a,c,i)); y[b].push_back(Segment(b,d,i)); minx=min(minx,a); maxx=max(maxx,c); miny=min(miny,b); maxy=max(maxy,d); } vector<Segment> ax,ay; if(!solve(x,ax,minx,maxx)||!solve(y,ay,miny,maxy)) puts("IMPOSSIBLE"); else { sort(ax.begin(),ax.end(),cmp); sort(ay.begin(),ay.end(),cmp); for(int i=0; i<n; ++i) printf("%d %d\n",ax[i].pos,ay[i].pos); } } return 0; }