uva 11134 fabled rooks (贪心)——yhx

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 rectan-
gle 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.
Input
The input consists of several test cases. The rst 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 le is terminated with the integer `0‘ on a line by itself.
Output
Your task is to nd such a placing of rooks that the above conditions are satised 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.



因为行和列并没有什么关系,所以只要把问题分成两个,如果都能满足,再进行配对即可。

那么问题就变成了在[1,n]上有n个区间,把n个整数恰好不重不漏地分配到每个区间。

很明显用贪心。

 1 #include<cstdio>
 2 #include<cstring>
 3 struct qj
 4 {
 5     int l,r,num;
 6 }q1,q2;
 7 qj a1[5010],a2[5010];
 8 int p1[5010],p2[5010],n;
 9 bool xy(qj a,qj b)
10 {
11     return a.l<b.l||(a.l==b.l&&a.r<b.r);
12 }
13 void st1(int l,int r)
14 {
15     int i,j,k;
16     qj mid=a1[(l+r)/2];
17     i=l;
18     j=r;
19     do
20     {
21         while (xy(a1[i],mid)) i++;
22         while (xy(mid,a1[j])) j--;
23         if (i<=j)
24         {
25             p1[a1[i].num]=j;
26             p1[a1[j].num]=i;
27             q1=a1[i];
28             a1[i]=a1[j];
29             a1[j]=q1;
30             i++;
31             j--;
32         }
33     }
34     while (i<=j);
35     if (l<j) st1(l,j);
36     if (i<r) st1(i,r);
37 }
38 void st2(int l,int r)
39 {
40     int i,j,k;
41     qj mid=a2[(l+r)/2];
42     i=l;
43     j=r;
44     do
45     {
46         while (xy(a2[i],mid)) i++;
47         while (xy(mid,a2[j])) j--;
48         if (i<=j)
49         {
50             p2[a2[i].num]=j;
51             p2[a2[j].num]=i;
52             q2=a2[i];
53             a2[i]=a2[j];
54             a2[j]=q2;
55             i++;
56             j--;
57         }
58     }
59     while (i<=j);
60     if (l<j) st2(l,j);
61     if (i<r) st2(i,r);
62 }
63 int main()
64 {
65     int i,j,k,m,p,q,x,y,z;
66     bool ok;
67     while (scanf("%d",&n)&&n)
68     {
69         for (i=1;i<=n;i++)
70         {
71             scanf("%d%d%d%d",&q1.l,&q2.l,&q1.r,&q2.r);
72             p1[i]=p2[i]=q1.num=q2.num=i;
73             a1[i]=q1;
74             a2[i]=q2;
75         }
76         st1(1,n);
77         st2(1,n);
78         ok=1;
79         for (i=1;i<=n;i++)
80           if (a1[i].l>i||a1[i].r<i||a2[i].l>i||a2[i].r<i)
81           {
82               ok=0;
83               break;
84           }
85         if (ok)
86           for (i=1;i<=n;i++)
87             printf("%d %d\n",p1[i],p2[i]);
88         else
89           printf("IMPOSSIBLE\n");
90     }
91 }

以上是经典的错误答案。(反正我开始就是这么错的)

把区间按左端点排序,第i个区间放整数i。

反例:[1,1],[1,3],[2,2]。照这个贪心思路找不到解。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MS(a) memset(a,0,sizeof(a))
 4 int l1[5010],r1[5010],l2[5010],r2[5010],p1[5010],p2[5010];
 5 int main()
 6 {
 7     int i,j,k,m,n,p,q1,q2,x,y,z,min1,min2;
 8     bool ok;
 9     while (scanf("%d",&n)&&n)
10     {
11         MS(p1);
12         MS(p2);
13         for (i=1;i<=n;i++)
14           scanf("%d%d%d%d",&l1[i],&l2[i],&r1[i],&r2[i]);
15         ok=1;
16         for (i=1;i<=n;i++)
17         {
18             q1=q2=-1;
19             min1=min2=1000000;
20             for (j=1;j<=n;j++)
21             {
22                 if (p1[j]==0&&l1[j]<=i&&r1[j]>=i&&r1[j]<min1)
23                 {
24                     q1=j;
25                     min1=r1[j];
26                 }
27                 if (p2[j]==0&&l2[j]<=i&&r2[j]>=i&&r2[j]<min2)
28                 {
29                     q2=j;
30                     min2=r2[j];
31                 }
32             }
33             if (q1==-1||q2==-1)
34             {
35                 ok=0;
36                 break;
37             }
38             p1[q1]=i;
39             p2[q2]=i;
40         }
41         if (ok)
42           for (i=1;i<=n;i++)
43             printf("%d %d\n",p1[i],p2[i]);
44         else
45           printf("IMPOSSIBLE\n");
46     }
47 }

正解:把按顺序枚举区间变成按顺序枚举点。对于每个点,找到它能放的、右端点最小的区间。

若不取这个区间而取另一个右端点更大的区间,会让之后的点选择变少。

时间: 2024-11-10 13:08:24

uva 11134 fabled rooks (贪心)——yhx的相关文章

UVA - 11134 Fabled Rooks[贪心 问题分解]

UVA - 11134 Fabled Rooks 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 rectan- gle given by its left-upper corner (xli,yli) and its right- lower corner

UVA 11134 Fabled Rooks 贪心

题目链接:UVA - 11134 题意描述:在一个n*n(1<=n<=5000)的棋盘上放置n个车,每个车都只能在给定的一个矩形里放置,使其n个车两两不在同一行和同一列,判断并给出解决方案. 算法分析:刚开始没有思路,后来看了别人的博客有了一点想法.我们把矩形的行和列分开解决,即n个车首先不能放置在同一行,然后判断n个车不能放置在同一列,如果都满足的话,即有正确的方法,否则就不行.那么怎样解决和判断在不在同一行并且是否可行呢,我们针对行而言,把这些行的坐标存入优先队列,首先取出最上面(行的标号

uva 11134 - Fabled Rooks(主要在贪心方法及其实现)

#用到了贪心方法. #这个贪心刚开始想错了方法,后来想到了新的方法,AC 刚开始错在了按左端点升序排序并从左往右取最左端能取的格子,这个方法显然不能符合要求 比如下面这组数据: 2 1 1 3 3 1 1 3 3 2 2 2 2 错误代码: #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; struct note {

(白书训练计划)UVa 11134 Fabled Rooks(贪心)

题目地址:UVa 11134 这题因为行与列是无关的,互无影响的.所以可以将行或列分开来计算.这就相当于转化成了在期间[1,n]内选择n个不同的整数,使得第i个整数在闭区间[Li,Ri]内.这就转换成了一个贪心问题了.但是注意不能先按照左端点排序,再按右端点排序,然后尽量往左边放,比如,(1,1),(1,3),(2,2),这样是不对的,应该按右端点为主关键字排序,再按左端点为次关键字排序.看到网上的方法全都是用每次选一个数后,都要在后面的区间中删去这个数,还要用到优先队列..感觉没必要这样做..

UVa 11134 Fabled Rooks(贪心)

题意  在n*n的棋盘上的n个指定区间上各放1个'车'  使他们相互不攻击   输出一种可能的方法 行和列可以分开看  就变成了n个区间上选n个点的贪心问题  看行列是否都有解就行   基础的贪心问题  对每个点选择包含它的最优未使用空间 #include <bits/stdc++.h> using namespace std; const int N = 5005; int xl[N], yl[N], xr[N], yr[N], x[N], y[N], n; bool solve(int a

UVA 11134 - Fabled Rooks(贪心 / 二分图 + 线段树优化连边)

题目地址:Fabled Rooks 题目大意:n * n 的棋盘上摆了 n <=10^5 个车,让他们两两不攻击,每个车必须摆在一个给定矩形里,给出一个解决方案? 1. 贪心 由于行列互不影响, 所以可以分两遍求.第一遍确定每个车的行数,第二遍确定列数. 以行为例,若从左到右扫描,则按照区间的右端点升序排序,因为如果扫到一个位置两枚棋子都可以放,则选择右端点较小的那个(右端点大的后面还有机会). 2. 二分图匹配 有个毒瘤老师把题目改成了这样:n * n 的棋盘上摆了 n <=10^5 个车,

Uva 11134 Fabled Rooks (问题分解 + 贪心放置)

题意: 给你n*n的棋盘,让放置n个车 使他们之间并不能相互攻击 附加条件是 给定n个车的放置区间 用左上角和右下角的坐标来表示 解题思路: 首先明确 横向的约束和纵向的约束其实并不互相影响 所以可以对横向和纵向单独求解 把问题变成两个一维的区间选点问题来求解 另外 在取点的时候 有贪心的思路在里面 对于n个区间 应该先选择区间中r最小的区间进行放置可放置的点 可以简单认为这是因为r越小的区间 其选择的灵活性就越低. 我刚开始的时候 是采取了先放置区间长度小的 在放置l小的区间 不正确. cod

UVA 11134 Fabled Rooks(贪心的妙用+memset误用警示)

题目链接: https://cn.vjudge.net/problem/UVA-11134 1 /* 2 问题 输入棋盘的规模和车的数量n(1=<n<=5000),接着输入n辆车的所能在的矩阵的范围,计算并输出使得每辆车横竖都不能相互攻击 3 的摆放方法,能则输出每辆车的坐标,不能则输出"IMPOSSIBLE". 4 解题思路 想想怎么将问题分解成几个小问题,不同行不同列的话,将其分成两个一维问题,采用DFS向下搜索,搜的时候注意每个车的 5 行区间和列区间,找到一种则直接

UVa 11134 - Fabled Rooks——[问题分解、贪心法]

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 rightlower corner (xri, yri), where 1 ≤ i ≤