【题目链接】
ybt 1230:寻找平面上的极大点
OpenJudge NOI 4.6 2704:寻找平面上的极大点
【题目考点】
1. 贪心
【解题思路】
题目中的极大点,直观理解就是右上方(不包含同一横线竖线)没有其他点的点。
解法1:选择满足 x x x大于 l x lx lx的点中 y y y最大的点中 x x x最大的点
1. 贪心选择性质的证明:
l
x
lx
lx表示上次选择的点的横坐标,初始值为-1。
对于给定的各个平面上的点
(
x
,
y
)
(x, y)
(x,y)
贪心选择:选择满足
x
x
x大于
l
x
lx
lx的点中
y
y
y最大的点中
x
x
x最大的点
解释:前提条件是:
x
>
l
x
x > lx
x>lx,找满足这一条件的所有点中
y
y
y最大的点,如果有多个点
y
y
y同时为最大值,选其中
x
x
x最大的点。
- 证明:对于第一次选择的点 ( x g , y g ) (x_g, y_g) (xg,yg),不存在其它的点 ( x , y ) (x, y) (x,y)满足 x ≥ x g 且 y ≥ y g x \ge x_g 且 y \ge y_g x≥xg且y≥yg。
假设:存在点 ( x m , y m ) (x_m, y_m) (xm,ym)不为 ( x g , y g ) (x_g, y_g) (xg,yg),满足 x m ≥ x g 且 y m ≥ y g x_m \ge x_g 且 y_m \ge y_g xm≥xg且ym≥yg。
第一次选择的点是 y y y最大的点,所以 y g ≥ y m y_g \ge y_m yg≥ym,所以有 y g = y m y_g = y_m yg=ym。
由于贪心选择为:如果 y y y最大的点有多个,那么选择其中 x x x最大的
点,所以有 x g ≥ x m x_g\ge x_m xg≥xm,进而 x g = x m x_g = x_m xg=xm。
因此 ( x m , y m ) (x_m, y_m) (xm,ym)与 ( x g , y g ) (x_g, y_g) (xg,yg)是同一个点,而假设二者不是同一个点,假设不成立,原命题得证。
- 证明:假设进行了k次进行贪心选择,第k次贪心选择到的点的横坐标为 l x lx lx,第k+1次贪心选择,选择到点 ( x g , y g ) (x_g,y_g) (xg,yg)。证明不存在其它的点 ( x , y ) (x, y) (x,y)满足 x ≥ x g 且 y ≥ y g x \ge x_g 且 y \ge y_g x≥xg且y≥yg。
假设:存在点 ( x m , y m ) (x_m, y_m) (xm,ym)不为 ( x g , y g ) (x_g, y_g) (xg,yg),满足 x m ≥ x g 且 y m ≥ y g x_m \ge x_g 且 y_m \ge y_g xm≥xg且ym≥yg。
由于 y g y_g yg是满足 x m > l x x_m>lx xm>lx的点中 y y y坐标的最大值,所以当 x m > l x x_m>lx xm>lx时不可能有 y m > y g y_m>y_g ym>yg。
如果 y m > y g y_m > y_g ym>yg,那么一定有 x m ≤ l x x_m \le lx xm≤lx,而已知 x g > l x x_g > lx xg>lx,那么有 x g > x m x_g > x_m xg>xm,与假设相悖。
如果 y m = y g y_m = y_g ym=yg,由于 y y y相同时, x g x_g xg是其中最大的,所以有: x g ≥ x m x_g \ge x_m xg≥xm,进而 x g = x m x_g = x_m xg=xm,所以 ( x m , y m ) (x_m, y_m) (xm,ym)与 ( x g , y g ) (x_g, y_g) (xg,yg)是同一个点,这与假设相悖。
原命题得证。
2. 具体做法
将所有点排序,排序规则为:y坐标大的排在前面;如果y坐标相同,x坐标大的排在前面。
设变量lx初值为-1。
顺序遍历点的数组,选择满足x >= lx
的点,如果选择了一个点,更新lx,使lx的值为这个点的横坐标。
解法2:选择满足 y y y大于 l y ly ly的点中 x x x最大的点中 y y y最大的点
该解法原理与解法1相似,不再赘述。
ly初值为-1。
由于该解法得到的点的x坐标是从大到小排列的,所以还得做一下逆序。
【题解代码】
解法1:选择满足 x x x大于 l x lx lx的点中: y y y最大的点中 x x x最大的点
#include<bits/stdc++.h>
using namespace std;
#define N 105
struct Point
{
int x, y;
};
bool cmp(Point a, Point b)
{
if(a.y == b.y)
return a.x > b.x;
else
return a.y > b.y;
}
int main()
{
Point a[N];
int n, lx = -1;
bool isFirst = true;
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i].x >> a[i].y;
sort(a+1, a+1+n, cmp);
for(int i = 1; i <= n; ++i)
{
if(a[i].x > lx)
{
lx = a[i].x;
if(isFirst)
isFirst = false;
else
cout << ',';
cout << '(' << a[i].x << ',' << a[i].y << ')';
}
}
return 0;
}
解法2:选择满足 y y y大于 l y ly ly的点中: x x x最大的点中 y y y最大的点
#include<bits/stdc++.h>
using namespace std;
#define N 105
struct Point
{
int x, y;
bool operator < (const Point &b) const
{//横坐标大的排在前面,横坐标相等时,纵坐标大的排在前面
if(x == b.x)
return y > b.y;
else
return x > b.x;
}
void show()
{
printf("(%d,%d)", x, y);
}
};
int main()
{
vector<Point> vec;
Point p;
stack<Point> stk;
int n, ly = -1;
bool isFirst = true;
cin >> n;
for(int i = 1; i <= n; ++i)
{
cin >> p.x >> p.y;
vec.push_back(p);
}
sort(vec.begin(), vec.end());
for(int i = 0; i < n; ++i)
{
if(vec[i].y > ly)
{
ly = vec[i].y;
stk.push(vec[i]);//从大到小得到各个点,要做逆序才能从小到大输出
}
}
while(stk.empty() == false)//逆序输出
{
Point u = stk.top(); stk.pop();
if(isFirst)
isFirst = false;
else
putchar(',');
u.show();
}
return 0;
}