UVa11134 Fabled Rooks (问题分解+贪心)

链接:http://vjudge.net/problem/34086

分析:两个车相互攻击的条件是出于同一行或者同一列,因此不相互攻击的条件就是不在同一行,也不在同一列。可以看出:行和列是无关的,因此可以把原题分解成两个一维问题。把行区间和列区间拆开,用一个index变量记录行区间和列区间属于哪一个车的进行编号,假设车的行区间为[a,b],将所有行区间按b的值从小到大排序,用贪心的思想,从排好序的第一个区间开始,优先放在行序号小的位置,列区间的处理方法与上述行的处理方法相同。最后按编号将行和列的坐标重新组合输出。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5
 6 struct Interval {
 7     int index;
 8     int begin;
 9     int end;
10     bool operator < (const Interval& b) const {
11         return end < b.end;
12     }
13 };
14
15 const int maxn = 5000 + 5;
16
17 int n;
18 Interval x[maxn], y[maxn];
19 pair<int, int> result[maxn];
20 int vis[maxn];
21
22 int main() {
23     while (cin >> n && n) {
24         for (int i = 0; i < n; i++) {
25             x[i].index = i;
26             y[i].index = i;
27             cin >> x[i].begin;
28             cin >> y[i].begin;
29             cin >> x[i].end;
30             cin >> y[i].end;
31         }
32         sort(x, x + n);
33         bool ok = true;
34         memset(vis, 0, sizeof(vis));
35         for (int i = 0; i < n; i++) {
36             int j;
37             for (j = x[i].begin; j <= x[i].end; j++) {
38                 if (!vis[j]) {
39                     vis[j] = 1;
40                     result[x[i].index].first = j;
41                     break;
42                 }
43             }
44             if (j > x[i].end) {
45                 ok = false;
46                 break;
47             }
48         }
49         if (ok) {
50             sort(y, y + n);
51             memset(vis, 0, sizeof(vis));
52             for (int i = 0; i < n; i++) {
53                 int j;
54                 for (j = y[i].begin; j <= y[i].end; j++) {
55                     if (!vis[j]) {
56                         vis[j] = 1;
57                         result[y[i].index].second = j;
58                         break;
59                     }
60                 }
61                 if (j > y[i].end) {
62                     ok = false;
63                     break;
64                 }
65             }
66         }
67         if (!ok) cout << "IMPOSSIBLE" << endl;
68         else for (int i = 0; i < n; i++) cout << result[i].first << " " << result[i].second << endl;
69     }
70     return 0;
71 }
时间: 2025-01-05 22:55:35

UVa11134 Fabled Rooks (问题分解+贪心)的相关文章

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

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

uva11134 - Fabled Rooks(问题分解,贪心法)

这道题非常好,不仅用到了把复杂问题分解为若干个熟悉的简单问题的方法,更是考察了对贪心法的理解和运用是否到位. 首先,如果直接在二维的棋盘上考虑怎么放不好弄,那么注意到x和y无关(因为两个车完全可以在同一条斜线上,这点和皇后问题不一样),那么就可以分别考虑两个一维的问题:这是一种区间选点问题,在每个区间里都只选一个点,最后这些点分别是1到n.这就联想到这样一个经典的贪心法解决的区间选点问题:数轴上有n个闭区间[ai,bi],选取尽量少的点,使得每个区间都至少含有一个点.这个问题的解决方法就是把所有

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个车,使得它们所在的行和列均不同,而且分别处于第 i 个矩形中. 解法:问题分解+贪心. 由于行.列不相关,所以可以先把行和列均不同的问题分解为2个“在区间[1,n]中选择n个不同的整数,使得第 i 个整数在[Li,Ri]内”的问题. 接下来的贪心很重要:先使区间R从小到大排序,再L.这样在每个合法区间段中尽量往左边选数的情况下,就能保证每个区间的右边一段是灵活合法的,而若R1=R2,由于是从左开始填数,这并不影响.反正我是没有找到反例的......而不像我(

L - Fabled Rooks(中途相遇法和贪心)

Problem F: 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 right-lower corner (xri

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 个车,