一道算法题--连连看

本文介绍了一种用于判断连连看游戏中两个点是否可以连线的算法。该算法通过判断两点是否在同一直线上或者通过一次转折连接来确定是否可以消除。文章提供了具体的实现代码,并分析了算法的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

群里的小伙伴发了一道在题目,判断一个棋盘上连连看的两个点是否可以消除。

原题目的点参考:

http://acm.hdu.edu.cn/showproblem.php?pid=1175


思路:参考了这篇blog

http://blog.youkuaiyun.com/artzok/article/details/51622782

大概意思,两个点最多通过两次折点相连分两种情况:

1)两点在一条直线上,那么两点可以直接连通。判断是否是这种情况

2)如果两点不在一直线上,从其中一个点出发往4个方向引点,只要引出的任意一点只经过一次拐点可以到达两一个点,则两个点(最大这点两次)可以相连。

代码实现如下:

#include <iostream>

#define N (1024)
int map[N][N] = { 0 };
/**
* test that whether point 1 and point 2 is connected without corner.
*/
bool ZeroCornerLink(int array[][N], int x1, int y1, int x2, int y2)
{
	// p1 and p2 can't connected without corner.
	if (x1 != x2 && y1 != y2)
		return false;

	int offsetX = (x2 > x1) ? 1 : ((x2 < x1 ? -1 : 0));
	int offsetY = (y2 > y1) ? 1 : ((y2 < y1 ? -1 : 0));

	for (int y = y1 + offsetY, x = x1 + offsetX; x != x2 || y != y2;
		x += offsetX, y += offsetY)
	{
		if (array[x][y] != 0)
			return false;
	}
	return true;
}

/**
* test that whether point 1 and point 2 is connected with only one corner.
*/
bool OneCornerLink(int arry[][N], int x1, int y1, int x2, int y2)
{
	// p1 and p2 can't connected without corner.
	if (x1 == x2 || y1 == y2)
		return false;

	int offsetX = (x2 > x1) ? 1 : ((x2 < x1 ? -1 : 0));
	int offsetY = (y2 > y1) ? 1 : ((y2 < y1 ? -1 : 0));

	// scan from X offset at first.
	bool direction = true;  // true to indicate to scan from X first.   
	for (int i = 0; i < 2; i++)
	{
		int x = x1, y = y1;
		direction = (i == 0) ? true : false;
		while (x != x2 || y != y2)
		{
			if (arry[x][y] != 0)
				break; // we have meet a block.
			if (direction && x == x2)
				direction = false; // change direction
			if (!direction && y == y2)
				direction = true;  // change direction

			if (direction)
				x += offsetX;
			else
				y += offsetY;
		}
		if (x == x2 && y == y2)
			return true; // it is connected.
	}
	return false;
}
int main(int argc, char **argv)
{
	int mapRows, mapCols, nQueries;
	while (scanf("%d%d", &mapRows, &mapCols) && mapRows)
	{
		for (int i = 1; i <= mapRows; i++)
		{
			for (int j = 1; j <= mapCols; j++)
				scanf("%d", &map[i][j]);
		}

		scanf("%d", &nQueries);
		while (nQueries--)
		{
			int x1, y1, x2, y2;
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);

			if (map[x1][y1] != map[x2][y2] || map[x1][y1] == 0 || x1 == x2&&y1 == y2)
			{
				printf("NO\n");
				continue;
			}

			if (ZeroCornerLink(map, x1, y1, x2, y2))
			{
				printf("Yes\n");
				continue;
			}
			else // corner link.
			{
				bool bConnected = false;
				// scan from up-down
				for (int x = x1 + 1, y = y1; !bConnected && x <= mapRows; ++x)
				{
					if (map[x][y] != 0) // block this direction
						break;
					if (OneCornerLink(map, x, y, x2, y2))
						bConnected = true;
				}
					
				// scan from down-up
				for (int x = x1 - 1, y = y1; !bConnected && x > 0; --x)
				{
					if (map[x][y] != 0) // block this direction
						break;
					if (OneCornerLink(map, x, y, x2, y2))
						bConnected = true;
				}
					
				// scan from left-right
				for (int x = x1, y = y1 + 1; !bConnected && y <= mapCols; ++y)
				{
					if (map[x][y] != 0) // block this direction
						break;
					if (OneCornerLink(map, x, y, x2, y2))
						bConnected = true;
				}
					
				// scan from right-left
				for (int x = x1, y = y1 - 1; !bConnected && y > 0; --y)
				{
					if (map[x][y] != 0) // block this direction
						break;
					if (OneCornerLink(map, x, y, x2, y2))
						bConnected = true;
				}
				if (bConnected)
					printf("Yes\n");
				else
					printf("No\n");
			}		
		}
	}
    return 0;
}


复杂度分析:

假设输入的数组是 M x N

则一次扫描,外层4个循环最多扫描的次数为 M+N

ZeroCornerLink复杂度是 O(Max(M, N)),

OneCornerLink扫描次数为最多两个方向2 *(M+N)

因此最坏情况下的复杂度为 O((M+N)^2)

内循环应该有重复扫描的路线,但是并未带来数量级的复杂度提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值