UVa 11134 - Fabled Rooks

链接:

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 }

 

posted @ 2017-12-17 00:08  Ctfes  阅读(119)  评论(0编辑  收藏  举报