链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2075
题意:
你的任务是在n*n的棋盘上放n(n≤5000)个车,使得任意两个车不相互攻击,且第i个车在一个给定的矩形Ri之内。
用4个整数xli, yli, xri, yri(1≤xli≤xri≤n,1≤yli≤yri≤n)描述第i个矩形,其中(xli,yli)是左上角坐标,(xri,yri)是右下角坐标,
则第i个车的位置(x,y)必须满足xli≤x≤xri,yli≤y≤yri。如果无解,输出IMPOSSIBLE;否则输出n行,依次为第1,2,…,n个车的坐标。
分析:
问题分解 + 贪心
两个车相互攻击的条件是处于同一行或者同一列,因此不相互攻击的条件就是不在同一行,也不在同一列。
可以看出:行和列是无关的,因此可以把原题分解成两个一维问题。在区间[1~n]内选择n个不同的整数,使得第i个整数在闭区间[Li, Ri]内。
贪心策略:以x坐标为例。对于每个区间来说,都应优先选择较左边的点,这样可以最大程度地利用各个点。
首先按R值从小到大排序,这样可以避免R值较大的区间比R值较小的区间首先占据较左边的点,即优先考虑较左边的区间,让选择的空间增加。
再按L值从小到大排序,也是为了最大程度地利用各个点,让选择的空间增加。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int UP = 5000 + 5; 7 8 int n, coor, ans[UP][2]; 9 10 struct RANGE { 11 int id, L[2], R[2]; 12 bool operator < (const RANGE& that) const { 13 if(R[coor] != that.R[coor]) return R[coor] < that.R[coor]; 14 return L[coor] < that.L[coor]; 15 } 16 } ran[UP]; 17 18 bool solve(int coor){ 19 sort(ran, ran + n); 20 bool used[UP]; 21 memset(used, false, sizeof(used)); 22 for(int t, i = 0; i < n; i++){ 23 for(t = ran[i].L[coor]; t <= ran[i].R[coor]; t++){ 24 if(used[t]) continue; 25 used[t] = true; 26 ans[ran[i].id][coor] = t; 27 break; 28 } 29 if(t > ran[i].R[coor]) return false; 30 } 31 return true; 32 } 33 34 int main(){ 35 while(scanf("%d", &n) && n){ 36 for(int i = 0; i < n; i++){ 37 ran[i].id = i; 38 scanf("%d%d", &ran[i].L[0], &ran[i].L[1]); 39 scanf("%d%d", &ran[i].R[0], &ran[i].R[1]); 40 } 41 if(!solve(coor = 0) || !solve(coor = 1)) printf("IMPOSSIBLE\n"); 42 else for(int i = 0; i < n; i++) printf("%d %d\n",ans[i][0],ans[i][1]); 43 } 44 return 0; 45 }