【c++】曲线谜题

题目描述:

果老师在玩一个曲线迷题游戏。

在这个游戏中,有一个r\times c 的矩形网格,对于整数i\left ( 1\leq i \leq N\right )会被填入网格中\left ( x_i1{},y_i1{} \right )\left ( x_i2{},y_i2 \right )两个网格。

现在果老师会尝试用曲线连接所有两两相同的数字,使得曲线不会出网格外并且不会交叉。

果老师希望你能帮他判断是否可能。

输入格式:

输出的第一行为三个正整数R,C,N

接下来的N,每行四个整数x_i1{},y_i1{},x_i2{},y_i2{}。表示i填入的网格坐标。

1\leq R,C\leq 10^{8},1\leq N\leq 10^{5}

0\leq x _i1{},x_i2{} \leq R\left ( 1\leq i\leq N\right )

0\leq y_i1{},y_i2{}\leq C(1\leq i\leq N)

给出的坐标点都不重合,所有输入的值都是整数。

输出格式

输入可能输出YES,否则输出NO

样例输入1

4 2 3
0 1 3 1
1 1 4 1
2 0 2 2

样例输出1

YES 

样例输入2

 2 2 4
0 0 2 2
2 0 0 1
0 2 1 2
1 1 2 1

样例输出 2

 NO

 样例输入 3

5 5 7
0 0 2 4
2 3 4 5
3 5 5 2
5 5 5 4
0 3 5 1
2 2 4 4
0 5 4 1

 样例输出 3

YES

样例输入 4

1 1 2
0 0 1 1
1 0 0 1

 样例输出 4

NO

提示

此题来源于NKOJ P7812

(以下题解仅供学习理解与思路分享,严禁抄袭)

 好,那么我们开始

再做这道题之前,我们要明确这个游戏怎么玩

以下给出一个样例

把相同颜色连在一起
每两条线相交为一个交叉
问最少有几个交叉

在这里大家可以思考一下
答案是两的交叉
如下图

通过观察我们不难发现 
两个交叉分别
黄色+蓝色
褐色+蓝色

三条线都有一个共同点
就是两个端点都在边界上

那么我们就可以只看两端点都在边界上的线
也就是把图形分成两半的线
因为其他线都有一个端点在图中
我们就可以绕过端点从而不发生交叉

因为只有两端都在边界上的点才会交叉,那么正方形里面的线就可以不考虑了了
这个时候我们把正方形的四边拆开(以下均采用正时针拆开)
就能进行降维,从而变成一维图像
如下图

 如果在一维图中交叉的就一定交叉
这里我们可以用排序+遍历
但我介绍一种更简单的方法

我们生成一个栈
把生成好的一维数组挨个入栈
再在入栈前一个判断
如果这个点的编号与栈顶相同
那么就删除栈顶元素
此元素也不在入栈
代表这条线不与其他任何线相交
执行完后,如果栈为空则没有交叉
反之则有交叉

理论成立,那么实践 

首先建立数据结构

struct node{
	int x;
	int y;//x,y均为坐标 
	int id;//点的编号 
	int opt;//点在哪条边上 
}a[200005];

 然后判断点在哪条边上

int get(int x,int y){
	if(x==0) return 1;//如果x=0则在上边 
	if(y==c) return 2;//如果y=c则在右边 
	if(x==r) return 3;//如果x=r则在下边 
	if(y==0) return 4;//如果y=0则在左边 
}

将两边都在边界上的点存入a数组后再进行拆开

int cmp(node x,node y){//按边排序 
	if(x.opt==y.opt){//如果在同一边则特殊处理 
	if(x.opt==1){
		return x.y<y.y;//从小到大 
	}
	if(x.opt==2){
		return x.x<y.x;//从小到大 
	}
	if(x.opt==3){
		return x.y>y.y;//从大到小 
	}
	if(x.opt==4){
		return x.x>y.x;//从大到小 
	}		
	}
	return x.opt<y.opt;
}

最后进栈处理

	for(int i=1;i<=cnt;i++){
		if(!s.empty()&&a[i].id==s.top()){//如果这个点的编号与栈顶相同,那么就删除栈顶元素,此元素也不在入栈 
			s.pop();
		}else{
			s.push(a[i].id);//如果相同则入栈 
		}
	}

最后进行输出

完结撒花!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hear the Wind Sing.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值