【题解】【信奥一本通T1230】【贪心】——寻找平面上的极大点

寻找平面上的极大点

通往信奥一本通的传送门

题目描述

在一个平面上,如果有两个点 ( x , y ) (x,y) (x,y) ( a , b ) (a,b) (a,b),如果说 ( x , y ) (x,y) (x,y)支配了 ( a , b ) (a,b) (a,b),这是指 x ≥ a x\geq a xa y ≥ b y\geq b yb;

用图形来看就是 ( a , b ) (a,b) (a,b)坐落在以 ( x , y ) (x,y) (x,y)为右上角的一个无限的区域内。

给定 n n n个点的集合,一定存在若干个点,它们不会被集合中的任何一点所支配,这些点叫做极大值点。

编程找出所有的极大点,按照 x x x坐标由小到大,输出极大点的坐标。本题规定: n n n不超过 100 100 100,并且不考虑点的坐标为负数的情况。

输入格式

输入包括两行,第一行是正整数 n n n,表示是点数,第二行包含 n n n个点的坐标。
坐标值都是整数,坐标范围从 0 0 0 100 100 100,输入数据中不存在坐标相同的点。

输出格式

x x x轴坐标最小到大的顺序输出所有极大点。
输出格式为: ( x 1 , y 1 ) (x_1,y_1) (x1,y1), ( x 2 , y 2 ) (x_2,y_2) (x2,y2),… ( x k , y k ) (x_k,y_k) (xk,yk)
注意:输出的每个点之间有,分隔,最后一个点之后没有,,少输出和多输出都会被判错。

输入输出样例

输入 #1

5
1 2 2 2 3 1 2 3 1 4

输出 #1

(1,4),(2,3),(3,1)

提示

在这里插入图片描述

解法1.暴力枚举

1.1.题意解析

    直接暴力枚举所有点,如果这个点被"支配",那么就标记。否则就在后面直接输出。不过多阐述。

1.2.AC代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
int n,tot,vis[MAXN];//用vis标记这个点是否不是"极大点"
struct point//储存每一个点的信息 
{
	int x,y;
}a[MAXN];
bool cmp(point a,point b)//输出需要,排序规则 
{
	if(a.x==b.x)return a.y<b.y;
	else return a.x<b.x;
}
int main()
{
	scanf("%d",&n);tot=n;//用tot储存"极大点"的个数 
	for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)//循环判断是否被"支配" 
	        if(a[i].x<=a[j].x&&a[i].y<=a[j].y&&i!=j)
	        {//如果被"支配" 
	        	vis[i]=1;
				tot--;
				break;
			}
	for(int i=1,j=1;i<=n&&j<=tot;i++)
	    if(!vis[i])//不被任何点支配,就是"极大点" 
	    {
	    	printf("(%d,%d)",a[i].x,a[i].y);
	    	if(j++<tot)putchar(',');//不是最后一个点,输出, 
		}
    return 0;
}

解法2.贪心

2.1.题意解析

    上述做法的时间复杂度是 O ( n 2 ) O(n^2) O(n2),还有没有改进的办法?

    观察上面的这张图(给你们搬到下面来了)
在这里插入图片描述
    如果将这张图倒过来看,将是这样的场景。(将就着看吧)
在这里插入图片描述
    我们可以考虑将每一个点按y坐标从大到小排序。在后面的遍历中,除非有点能超过它的 x x x坐标,不然就绝对会被它支配。读者可以自行思考并设法证明。

    在代码实现中,使用一个变量lastx记录当前最后一次贪心选择 x x x坐标。其他就没什么好讲的了。这种办法可以将时间复杂度降到 O ( n log ⁡ n ) O(n\log n) O(nlogn)(排序)。只可意会不可言传,直接看代码。

2.2.AC代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
struct point//储存每一个点的信息 
{
    int x,y;
}a[MAXN];
bool cmp(point a,point b)
{
    if(a.y==b.y)return a.x>b.x;
    return a.y>b.y;//优先按y坐标排序 
}
int main()
{
    int n,lastx=-1,is_first=1;
    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>lastx)//符合条件 
        {
            lastx=a[i].x;
            if(is_first)is_first=false;
            else putchar(',');
            printf("(%d,%d)",a[i].x,a[i].y);
        }
	return 0;
}

喜欢就订阅此专辑吧!

【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。

欢迎扫码关注蓝胖子编程教育
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子教编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值