NKOJ P7812 曲线谜题

题目传送门

曲线谜题

时间限制 : - MS 空间限制 : - KB

评测说明 : 1s 256MB


问题描述

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

在这个游戏中,有一个  R * C 的矩形网格,对于整数 i(1 <= i <= N) 会被填入网格中

(x[i]1,y[i ]1)和 (x[i]2,y[i]2) 两个网格。

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

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

输入格式

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

接下来的N行,每行两个坐标(x[i]1,y[i ]1)和 (x[i]2,y[i]2) 。表示 i 填入的网格坐标。

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

输出格式

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


思路:

这道题比较难

先来思考一下:

图片(高清)


 

只有两个交点,如图所示。

可见,相交的点都是由两端都在边上的点。

因为两端没有在四边上的会留出空隙,供其他线穿过,不影响整体。

所以我们只讨论两端都在边上的点。

我们将上图转化为二维:

然后连点:

可见,相交的点就是上图中的两个交点。 

这道题就变得简单了。

第一步:将图像的四条边展开

第二步:按特定顺序排序

第三步:将颜色入栈,如果栈顶与将要入栈的颜色相同,弹出栈顶。

第四步:如果栈为空,输出"YES",否则输出"NO"。

第一步:

bool check(int x, int y)
{
	if(x == 0 || x == r || y == 0 || y == c)
		return true;
	return false;
}

int choose(int x, int y)
{
	if(x == 0)
		return 1;
	if(y == c)
		return 2;
	if(x == r)
		return 3;
	if(y == 0)
		return 4;
}

//......

for(int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(check(x1,y1)==true&&check(x2,y2)==true)
		{
			member[++cnt].x = x1;
			member[cnt].y = y1;
			member[cnt].id = choose(x1,y1);
			member[cnt].color = i;
			member[++cnt].x = x2;
			member[cnt].y = y2;
			member[cnt].id = choose(x2,y2);
			member[cnt].color = i;
		}
	}

 第二步:

bool operator < (node x, node y)    //重载
{
	if(x.id == y.id)
	{
		if(x.id == 1)
			return x.y < y.y;
		if(x.id == 2)
			return x.x < y.x;
		if(x.id == 3)
			return x.y > y.y;
		if(x.id == 4)
			return x.x > y.x;
	}
	return x.id < y.id;
}
//......
sort(member + 1, member + 1 + cnt)

第三步:

	for(int i=1;i<=cnt;i++)
	{
		if(!stk.empty() && member[i].color == stk.top())
			stk.pop();
		else
			stk.push(member[i].color);
	}

第四步:

if(stk.empty())
{
	printf("YES\n");
}
else
{
	printf("NO\n");
}
return 0;

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e8;

int c,r,n;
struct node
{
	int x;
	int y;
	int color;
	int id;
};
node member[N];

bool operator < (node x, node y)
{
	if(x.id == y.id)
	{
		if(x.id == 1)
			return x.y < y.y;
		if(x.id == 2)
			return x.x < y.x;
		if(x.id == 3)
			return x.y > y.y;
		if(x.id == 4)
			return x.x > y.x;
	}
	return x.id < y.id;
}

bool check(int x, int y)
{
	if(x == 0 || x == r || y == 0 || y == c)
		return true;
	return false;
}

int choose(int x, int y)
{
	if(x == 0)
		return 1;
	if(y == c)
		return 2;
	if(x == r)
		return 3;
	if(y == 0)
		return 4;
}

stack<int> stk;

int main()
{
	int cnt = 0;
	scanf("%d%d%d",&r,&c,&n);
	for(int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(check(x1,y1)==true&&check(x2,y2)==true)
		{
			member[++cnt].x = x1;
			member[cnt].y = y1;
			member[cnt].id = choose(x1,y1);
			member[cnt].color = i;
			member[++cnt].x = x2;
			member[cnt].y = y2;
			member[cnt].id = choose(x2,y2);
			member[cnt].color = i;
		}
	}
	
	sort(member + 1, member + 1 + cnt);
	
	for(int i=1;i<=cnt;i++)
	{
		if(!stk.empty() && member[i].color == stk.top())
			stk.pop();
		else
			stk.push(member[i].color);
	}
	if(stk.empty())
	{
		printf("YES\n");
	}
	else
	{
		printf("NO\n");
	}
	return 0;
}

AC记录


The end

最后:制作不易,点个赞吧,求求了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值