题意:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内(从左上角到右下角)。
1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点。
2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序;每次在一个区间选点的时候,按从左到右选没有被前面区间选过的点。(从这个区间开始选最大程度的防止了以后的区间没有点可以选(因为右端点选的是最小的))
错误的贪心方法:把所有区间按左端排序,然后每次选能选的最左边的。反例:[1,1],[1,3],[2,2];(这种贪心发并不能保证以后的区间有点可以选,某些区间可能更长,取后面的点更合适)
#include <iostream> #include <cstring> #include <algorithm> using namespace std; struct node{ int l,r,id; }x[5500],y[5500],ans[5500],ansx[5500],ansy[5500]; bool cmp(node a,node b){ return a.r<b.r; } bool cmp1(node a,node b){ return a.id<b.id; } int n; bool vis[5500]; bool solve(node *a,node *ans){ memset(vis,0,sizeof(vis)); int i,j; for(i=0;i<n;i++){ for(j=a[i].l;j<=a[i].r;j++){ if(vis[j]) continue; break; } if(j>a[i].r) return false; ans[i].l=j;//将其用来保存答案 ans[i].id=a[i].id; vis[j]=true; } return true; } int main() { ios::sync_with_stdio(false);cin.tie(0); while(cin>>n&&n!=0){ for(int i=0;i<n;i++){ cin>>x[i].l>>y[i].l>>x[i].r>>y[i].r; x[i].id=y[i].id=i; } sort(x,x+n,cmp); sort(y,y+n,cmp); if(solve(x,ansx)&&solve(y,ansy)){ sort(ansx,ansx+n,cmp1); sort(ansy,ansy+n,cmp1); for(int i=0;i<n;i++) { cout<<ansx[i].l<<" "<<ansy[i].l<<endl; } } else cout<<"IMPOSSIBLE"<<endl; } return 0; }