UVa 11134 (区间上的贪心) Fabled Rooks
这道题真是WA得我心力交瘁,好讨厌的感觉啊!
简直木有写题解的心情了
题意:
n×n的棋盘里,放置n个车,使得任意两车不同行且不同列,且第i个车必须放在给定的第i个矩形范围内。输出一种方案,即每个车的坐标,无解的话则输出“IMPOSSIBLE”
行和列是独立的,所以可以分开处理,将二维的转化成了一维区间上的取点问题:
有一个长度为n的区间,还有n个小区间,求一种方案,在每个小区间的范围取一个点,是的大区间上每个单位1的区间里都有点。
开始写的贪心是错误的:
按区间的左端点从小到大排序,然后右端点从小到大二级排序。
这里有个反例:
比如按这种方式排序后的区间是:[1, 3] [1, 3] [2, 2]
那么第一第二个点会放在前两个[1, 3]里面,而第三个点就放不下了。
但是显然这种情况是有合法方案的。
正确的贪心方式:
先对区间的右端点从小到大排序,然后左端点从大到小二级排序(满足区间短的先选)。
从区间的角度考虑:
然后对于每个区间,在它所覆盖的范围从左到右遍历,如果没有放点,就放进去。如果遍历完整个区间都没有点能放,就说明不存在合法方案。
从点考虑的话,我又WA掉了。。=_=||
将区间排序后,从第一个点开始,找到第一个能放进去的区间就放下。
下面是AC的代码君:
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 5000 + 10; 9 struct Node 10 { 11 int x1, x2, y1, y2; 12 int x, y; 13 int order; 14 }a[maxn]; 15 int n; 16 bool vis[maxn]; 17 18 bool cmp1(Node a, Node b) 19 { 20 return a.x2 < b.x2 || (a.x2 == b.x2 && a.x1 > b.x1); 21 } 22 23 bool cmp2(Node a, Node b) 24 { 25 return a.y2 < b.y2 || (a.y2 == b.y2 && a.y1 > b.y1); 26 } 27 28 bool cmp3(Node a, Node b) 29 { 30 return a.order < b.order; 31 } 32 33 int main(void) 34 { 35 #ifdef LOCAL 36 freopen("11134in.txt", "r", stdin); 37 #endif 38 39 while(scanf("%d", &n) == 1 && n) 40 { 41 for(int i = 0; i < n; ++i) 42 { 43 scanf("%d%d%d%d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2); 44 a[i].order = i; 45 } 46 47 memset(vis, false, sizeof(vis)); 48 flag = true; 49 sort(a, a + n, cmp1); 50 for(int i = 0; i < n; ++i) 51 { 52 for(j = a[i].x1; j <= a[i].x2; ++j) 53 { 54 if(!vis[j]) 55 { 56 vis[j] = true; 57 a[i].x = j; 58 break; 59 } 60 } 61 if(j > a[i].x2) 62 { 63 flag = false; 64 break; 65 } 66 } 67 68 if(flag) 69 { 70 memset(vis, false, sizeof(vis)); 71 sort(a, a + n, cmp2); 72 for(int i = 0; i < n; ++i) 73 { 74 for(j = a[i].y1; j <= a[i].y2; ++j) 75 { 76 if(!vis[j]) 77 { 78 vis[j] = true; 79 a[i].y = j; 80 break; 81 } 82 if(j > a[i].y2) 83 { 84 flag = false; 85 break; 86 } 87 } 88 } 89 } 90 91 if(flag) 92 { 93 sort(a, a + n, cmp3); 94 for(int i = 0; i < n; ++i) printf("%d %d\n", a[i].x, a[i].y); 95 } 96 else 97 puts("IMPOSSIBLE"); 98 } 99 100 return 0; 101 }