问题来源:刘汝佳《算法竞赛入门经典--训练指南》 P81:
问题描述:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内。
问题分析:1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点。
2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序;每次在一个区间选点的时候,按从左到右选没有被前面区间选过的点。(从这个区间开始选最大程度的防止了以后的区间没有点可以选(因为右端点选的是最小的))
错误的贪心方法:把所有区间按左端排序,然后每次选能选的最左边的。反例:[1,1],[1,3],[2,2];(这种贪心发并不能保证以后的区间有点可以选,某些区间可能更长,取后面的点更合适)
例题链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2075
例题:UVa 11134
11134 - Fabled Rooks
Time limit: 3.000 seconds
We would like to place n rooks, 1 ≤ n ≤ 5000, on a n×n board subject to the following restrictions
- The i-th rook can only be placed within the rectangle given by its left-upper corner (xli, yli) and its right-lower corner (xri, yri), where 1 ≤ i ≤ n, 1 ≤ xli ≤ xri ≤ n, 1 ≤ yli ≤ yri ≤ n.
- No two rooks can attack each other, that is no two rooks can occupy the same column or the same row.
The input consists of several test cases. The first line of each of them contains one integer number, n, the side of the board. n lines follow giving the rectangles where the rooks can be placed as described above. The i-th line among them gives xli, yli, xri, and yri. The input file is terminated with the integer `0‘ on a line by itself.
Your task is to find such a placing of rooks that the above conditions are satisfied and then output n lines each giving the position of a rook in order in which their rectangles appeared in the input. If there are multiple solutions, any one will do. Output IMPOSSIBLE if there is no such placing of the rooks.
Sample input
8 1 1 2 2 5 7 8 8 2 2 5 5 2 2 5 5 6 3 8 6 6 3 8 5 6 3 8 8 3 6 7 8 8 1 1 2 2 5 7 8 8 2 2 5 5 2 2 5 5 6 3 8 6 6 3 8 5 6 3 8 8 3 6 7 8 0
Output for sample input
1 1 5 8 2 4 4 2 7 3 8 5 6 6 3 7 1 1 5 8 2 4 4 2 7 3 8 5 6 6 3 7
代码实现:
1 #include "stdio.h" 2 #include "string.h" 3 #include "algorithm" 4 using namespace std; 5 6 #define N 5010 7 8 typedef struct 9 { 10 int id; 11 int l,r; 12 }Point; 13 14 int n; 15 bool mark[N]; 16 Point x[N],y[N],ans[N]; 17 Point ansx[N],ansy[N]; 18 19 bool cmp(Point a,Point b) { return a.r < b.r; } //按右端点最小的进行排序 20 21 bool cmp1(Point a,Point b){ return a.id < b.id;} //按id号还原顺序 22 23 bool solve(Point *a,Point *ans) 24 { 25 int i,j; 26 memset(mark,false,sizeof(mark)); 27 for(i=0; i<n; i++) 28 { 29 for(j=a[i].l; j<=a[i].r; j++) 30 { 31 if(mark[j]) continue; 32 break; 33 } 34 if(j>a[i].r) return false; 35 ans[i].l = j; //用ans[i].l保存答案 36 ans[i].id = a[i].id; 37 mark[j] = true; 38 } 39 return true; 40 } 41 42 int main() 43 { 44 int i; 45 while(~scanf("%d",&n),n!=0) 46 { 47 for(i=0; i<n; i++) 48 { 49 scanf("%d %d %d %d",&x[i].l,&y[i].l,&x[i].r,&y[i].r); 50 x[i].id = y[i].id = i; 51 } 52 sort(x,x+n,cmp); 53 sort(y,y+n,cmp); 54 if(solve(x,ansx) && solve(y,ansy)) 55 { 56 sort(ansx,ansx+n,cmp1); 57 sort(ansy,ansy+n,cmp1); 58 for(i=0; i<n; i++) 59 printf("%d %d\n",ansx[i].l,ansy[i].l); 60 } 61 else 62 printf("IMPOSSIBLE\n"); 63 } 64 return 0; 65 }