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 }

代码君

时间: 2025-01-02 13:28:22

UVa 11134 (区间上的贪心) Fabled Rooks的相关文章

nyoj891(区间上的贪心)

题目意思: 给一些闭区间,求最少须要多少点,使得每一个区间至少一个点. http://acm.nyist.net/JudgeOnline/problem.php?pid=891 例子输入 4 1 5 2 4 1 4 2 3 3 1 2 3 4 5 6 1 2 2 例子输出 1 3 1 题目分体: 区间贪心.我觉得区间上的贪心算法,最基本的还是排序的方式.仅仅要排序的方式合理.就能非常好的使用贪心,贪心的本质尽管是选择当前最优的解,作为全军最优解的一部分.假设排序不当回造成好的条件选择.本题仅仅给

nyoj891找点(区间上的贪心)

找点 时间限制:2000 ms  |  内存限制:65535 KB 难度:2 描述 上数学课时,老师给了LYH一些闭区间,让他取尽量少的点,使得每个闭区间内至少有一个点.但是这几天LYH太忙了,你们帮帮他吗? 输入 多组测试数据. 每组数据先输入一个N,表示有N个闭区间(N≤100). 接下来N行,每行输入两个数a,b(0≤a≤b≤100),表示区间的两个端点. 输出 输出一个整数,表示最少需要找几个点. 样例输入 4 1 5 2 4 1 4 2 3 3 1 2 3 4 5 6 1 2 2 样例

Uva 11134 传说中的车 贪心的思维

题目大意: 在一个n*n的棋盘上放置n个车,使得它们之间都不能互相攻击(任意两个车都不能同行或同列),并且,对于第i个车,限制它只能放在一个矩形区域内,(xli, yli),这个矩形的左上角顶点坐标是(xli, yli),右下角顶点坐标是 (xri, yri), 1 ≤ i ≤ n, 1 ≤ xli ≤ xri ≤ n, 1 ≤ yli ≤ yri ≤ n. 分析: 两个车相互攻击的条件是在同一行或列,可以看出,行和列是无关的,所以可以分解成两个一维问题. 问题就转化为在[1,n]选择n个数,使

01_传说中的车(Fabled Rooks UVa 11134 贪心问题)

问题来源:刘汝佳<算法竞赛入门经典--训练指南> P81: 问题描述:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内. 问题分析:1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点.  2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序:每次在一个区间

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(贪心)

题意  在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(主要在贪心方法及其实现)

#用到了贪心方法. #这个贪心刚开始想错了方法,后来想到了新的方法,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(贪心 / 二分图 + 线段树优化连边)

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

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

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