连连看算法:判断两个点是否能经过最多两次转折连通
连通情况有:
1.两点相邻
直接返回true
2.两点不相邻
进行横向搜索和纵向搜索
a. 横向搜索
求出两点分别从左右两边出发能到达的范围,然后再求出两个范围的交集
如果没有交集,则返回false
如果存在交集,则求交集中的维度是否存在一条直线连通,如图
上面的A的范围为[1,5),下面的A的范围为[1,3),它们的交集为[1,3),只需判断(2,1)和(4,1), 或者(2,2)和(4,2)是否连通
上面的A的范围为[4,5),下面的A的范围为[4,5),它们的交集为[4,5),只需判断(2,4)和(5,4)连通
上面的A的范围为[5,7),下面的A的范围为[1,7),它们的交集为[5,7),只需判断(2,5)和(4,5), 或者(2,6)和(4,6)是否连通
b. 纵向搜索 同理
为了避免每次去判断两点是否连通,我使用了2个数组初始化后分别记录横向和纵向的空白直线
struct line{
int begin;
int end;
line* pNext;
}
line* LineMap1[行数];
line* LineMap2[列数];
每次查询对应的行或列去找到相应的直线,只需判断该两点是否在这直线上即可,但每次删除点需要更新LineMap的值
还有,像两个点在同一行的时候,只需纵向搜索
相反,在同一列时,只需横向搜索.
代码还不完整,不过基本实现了插入,删除,判断是否连接的函数了
#ifndef LMAP_H
#define LMAP_H
#define assert(a) ;
#include <iostream>
using namespace std;
typedef int vType;
struct lPoint{
public:
lPoint():m_bExist(false){}
int m_nAbs;
int m_nOrd;
vType m_Value;
bool m_bExist;
};
struct lLine{
public:
lLine():m_pNext(NULL){}
lLine(int begin, int end):m_nBegin(begin),m_nEnd(end),m_pNext(NULL){}
int m_nBegin;
int m_nEnd;
lLine* m_pNext;
};
const int MAX_ABS_DFL = 10;
const int MAX_ORD_DFL = 10;
class lMap{
public:
void Init(int max_abs = MAX_ABS_DFL, int max_ord = MAX_ORD_DFL);
bool Insert(const int abs, const int ord, vType value);
bool Erase(const int abs, const int ord);
bool IsLinked(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
bool IsEmpty();
bool IsDead();
void PrintLineMap();
void PrintMap();
private:
void _Insert(const int abs, const int ord, vType value);
void _Erase(const int abs, const int ord);
bool DoCheckLinked(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
bool IsLinkedInOneAbs(const int pointA_ord, const int pointB_ord, const int point_abs);
bool IsLinkedInOneOrd(const int pointA_abs, const int pointB_abs, const int point_ord);
bool IsLinkedInSomeAbs(const int pointA_ord, const int pointB_ord, const int point_abs_begin, const int point_abs_end);
bool IsLinkedInSomeOrd(const int pointA_abs, const int pointB_abs, const int point_ord_begin, const int point_ord_end);
bool _CheckLinkedInAbs(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
bool CheckLinkedInAbs(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
bool _CheckLinkedInOrd(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
bool CheckLinkedInOrd(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord);
void GetCommonRange(int rangeA_begin, int rangeA_end, int rangeB_begin, int rangeB_end, int& range_begin, int& range_end);
private:
lPoint* m_pMap;
lLine** m_LineMap_abs;
lLine** m_LineMap_ord;
int m_nUsed;
int m_max_abs;
int m_max_ord;
};
void lMap::PrintMap()
{
cout << "map count:" << m_nUsed << endl;
for(int i = 1; i < m_max_abs - 1; ++i)
{
for(int j = 1; j < m_max_ord - 1; ++j)
{
if(m_pMap[i * m_max_ord + j].m_bExist)
cout << "| " << m_pMap[i * m_max_ord + j].m_Value << " ";
else
cout << "| ";
if(j == m_max_ord - 2)
cout << "|";
}
cout << endl;
}
}
void lMap::PrintLineMap()
{
cout << "LineMap_abs:" << endl;
for(int i = 0; i < m_max_abs; ++i)
{
cout << " < " << i << " > :";
lLine* pLine = m_LineMap_abs[i];
while(pLine != NULL)
{
cout << " (" << pLine->m_nBegin << ", " << pLine->m_nEnd << ") ";
pLine = pLine->m_pNext;
}
cout << endl;
}
cout << endl << "LineMap_ord:" << endl;
for(int i = 0; i < m_max_ord; ++i)
{
cout << " < " << i << " > :";
lLine* pLine = m_LineMap_ord[i];
while(pLine != NULL)
{
cout << " (" << pLine->m_nBegin << ", " << pLine->m_nEnd << ") ";
pLine = pLine->m_pNext;
}
cout << endl;
}
}
void lMap::Init(int max_abs, int max_ord)
{
m_nUsed = 0;
m_max_abs = max_abs + 2;
m_max_ord = max_ord + 2;
m_pMap = new lPoint[(m_max_abs) * (m_max_ord)];
m_LineMap_abs = new lLine*[m_max_abs];
for(int i = 0; i < m_max_abs; ++i)
m_LineMap_abs[i] = new lLine(0, m_max_ord);
m_LineMap_ord = new lLine*[m_max_ord];
for(int i = 0; i < m_max_ord; ++i)
m_LineMap_ord[i] = new lLine(0, m_max_abs);
}
bool lMap::IsEmpty()
{
return m_nUsed == 0;
}
bool lMap::IsDead()
{
return false;
}
bool lMap::IsLinked(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
if(!(m_pMap)[pointA_abs * m_max_ord + pointA_ord].m_bExist || !(m_pMap)[pointB_abs * m_max_ord + pointB_ord].m_bExist)
{
fprintf(stderr, "IsLinked: Point<%d, %d> or Point<%d, %d> not Exist!\n", pointA_abs, pointA_ord, pointB_abs, pointB_ord);
return false;
}
if(pointA_abs == pointB_abs && pointA_ord == pointB_ord)
{
fprintf(stderr, "IsLinked: Point<%d, %d> and Point<%d, %d> are the same Point!\n", pointA_abs, pointA_ord, pointB_abs, pointB_ord);
return false;
}
if((m_pMap)[pointA_abs * m_max_ord + pointA_ord].m_Value != (m_pMap)[pointB_abs * m_max_ord + pointB_ord].m_Value)
{
fprintf(stderr, "IsLinked: Point<%d, %d> and Point<%d, %d> are not the same Kind!\n", pointA_abs, pointA_ord, pointB_abs, pointB_ord);
return false;
}
return DoCheckLinked(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
}
bool lMap::Insert(const int abs, const int ord, vType value)
{
if(m_pMap[abs * m_max_ord + ord].m_bExist)
{
fprintf(stderr, "Insert: Point<%d, %d> Exist!\n", abs, ord);
return false;
}
_Insert(abs, ord, value);
m_nUsed++;
return true;
}
void lMap::_Insert(const int abs, const int ord, vType value)
{
m_pMap[abs * m_max_ord + ord].m_Value = value;
m_pMap[abs * m_max_ord + ord].m_bExist = true;
lLine* pLine = m_LineMap_abs[abs];
lLine* pTemp = pLine;
while(pLine != NULL)
{
if(ord < pLine->m_nEnd)
{
if(pLine->m_nEnd - pLine->m_nBegin == 1)
{
pTemp->m_pNext = pLine->m_pNext;
delete pLine;
}
else if(ord == pLine->m_nBegin)
pLine->m_nBegin++;
else if(ord == pLine->m_nEnd - 1)
pLine->m_nEnd--;
else
{
lLine* pNewLine = new lLine(ord + 1, pLine->m_nEnd);
pLine->m_nEnd = ord;
pNewLine->m_pNext = pLine->m_pNext;
pLine->m_pNext = pNewLine;
}
break;
}
pTemp = pLine;
pLine = pLine->m_pNext;
}
pLine = m_LineMap_ord[ord];
pTemp = pLine;
while(pLine != NULL)
{
if(abs < pLine->m_nEnd)
{
if(pLine->m_nEnd - pLine->m_nBegin == 1)
{
pTemp->m_pNext = pLine->m_pNext;
delete pLine;
}
else if(abs == pLine->m_nBegin)
pLine->m_nBegin++;
else if(abs == pLine->m_nEnd - 1)
pLine->m_nEnd--;
else
{
lLine* pNewLine = new lLine(abs + 1, pLine->m_nEnd);
pLine->m_nEnd = abs;
pNewLine->m_pNext = pLine->m_pNext;
pLine->m_pNext = pNewLine;
}
break;
}
pTemp = pLine;
pLine = pLine->m_pNext;
}
}
bool lMap::Erase(const int abs, const int ord)
{
if(!(m_pMap)[abs * m_max_ord + ord].m_bExist)
{
fprintf(stderr, "Erase: Point<%d, %d> not Exist!\n", abs, ord);
return false;
}
_Erase(abs, ord);
m_nUsed--;
return true;
}
void lMap::_Erase(const int abs, const int ord)
{
m_pMap[abs * m_max_ord + ord].m_bExist = false;
lLine* pLine = m_LineMap_abs[abs];
lLine* pTemp = pLine;
while(pLine != NULL)
{
if(ord < pLine->m_nBegin)
{
if(pLine->m_nBegin - pTemp->m_nEnd == 1)
{
pTemp->m_nEnd = pLine->m_nEnd;
pTemp->m_pNext = pLine->m_pNext;
delete pLine;
}
else if(ord == pLine->m_nBegin - 1)
pLine->m_nBegin--;
else if(ord == pTemp->m_nEnd)
pTemp->m_nEnd++;
else
{
lLine* pNewLine = new lLine(ord, ord + 1);
pTemp->m_pNext = pNewLine;
pNewLine->m_pNext = pLine;
}
break;
}
pTemp = pLine;
pLine = pLine->m_pNext;
}
pLine = m_LineMap_ord[ord];
pTemp = pLine;
while(pLine)
{
if(abs < pLine->m_nBegin)
{
if(pLine->m_nBegin - pTemp->m_nEnd == 1)
{
pTemp->m_nEnd = pLine->m_nEnd;
pTemp->m_pNext = pLine->m_pNext;
delete pLine;
}
else if(abs == pLine->m_nBegin - 1)
pLine->m_nBegin--;
else if(abs == pTemp->m_nEnd)
pTemp->m_nEnd++;
else
{
lLine* pNewLine = new lLine(abs, abs + 1);
pTemp->m_pNext = pNewLine;
pNewLine->m_pNext = pLine;
}
break;
}
pTemp = pLine;
pLine = pLine->m_pNext;
}
}
bool lMap::DoCheckLinked(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
if(pointA_abs == pointB_abs)
{
if(pointB_ord - pointA_ord == 1 || pointA_ord - pointB_ord == 1)
return true;
else
return CheckLinkedInOrd(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
}
if(pointA_ord == pointB_ord)
{
if(pointA_abs - pointB_abs == 1 || pointB_abs - pointA_abs == 1)
return true;
else
return CheckLinkedInAbs(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
}
if(CheckLinkedInAbs(pointA_abs, pointA_ord, pointB_abs, pointB_ord))
return true;
else
return CheckLinkedInOrd(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
}
bool lMap::IsLinkedInOneAbs(const int pointA_ord, const int pointB_ord, const int point_abs)
{
lLine* pLine = m_LineMap_abs[point_abs];
while(pLine != NULL)
{
if(pLine->m_nEnd > pointA_ord)
{
if(pLine->m_nBegin <= pointA_ord && pLine->m_nEnd > pointB_ord)
return true;
else
return false;
}
pLine = pLine->m_pNext;
}
}
bool lMap::IsLinkedInOneOrd(const int pointA_abs, const int pointB_abs, const int point_ord)
{
lLine* pLine = m_LineMap_abs[point_ord];
while(pLine != NULL)
{
if(pLine->m_nEnd > pointA_abs)
{
if(pLine->m_nBegin <= pointA_abs && pLine->m_nEnd > pointB_abs)
return true;
else
return false;
}
pLine = pLine->m_pNext;
}
}
bool lMap::IsLinkedInSomeAbs(const int pointA_ord, const int pointB_ord, const int point_abs_begin, const int point_abs_end)
{
for(int i = point_abs_begin; i < point_abs_end; ++i)
{
if(IsLinkedInOneAbs(pointA_ord, pointB_ord, i))
return true;
}
return false;
}
bool lMap::IsLinkedInSomeOrd(const int pointA_abs, const int pointB_abs, const int point_ord_begin, const int point_ord_end)
{
for(int i = point_ord_begin; i < point_ord_end; ++i)
{
if(IsLinkedInOneOrd(pointA_abs, pointB_abs, i))
return true;
}
return false;
}
bool lMap::CheckLinkedInAbs(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
if(pointA_abs < pointB_abs)
return _CheckLinkedInAbs(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
else
return _CheckLinkedInAbs(pointB_abs, pointB_ord, pointA_abs, pointA_ord);
}
bool lMap::_CheckLinkedInAbs(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
int pointA_ord_begin = pointA_ord, pointA_ord_end = pointA_ord + 1;
int pointB_ord_begin = pointB_ord, pointB_ord_end = pointB_ord + 1;
bool flag = false;
lLine* pLine = m_LineMap_abs[pointA_abs];
if(!m_pMap[pointA_abs * m_max_ord + pointA_ord - 1].m_bExist)
{
while(pLine != NULL)
{
if(pLine->m_nEnd == pointA_ord)
{
pointA_ord_begin = pLine->m_nBegin;
flag = true;
break;
}
pLine = pLine->m_pNext;
}
assert(pointA_ord_begin != pointA_ord);
}
if(!m_pMap[pointA_abs * m_max_ord + pointA_ord + 1].m_bExist)
{
if(flag)
{
pLine = pLine->m_pNext;
assert(pLine != NULL && pointA_ord + 1 == pLine->m_nBegin);
pointA_ord_end = pLine->m_nEnd;
flag = false;
}
else
{
while(pLine != NULL)
{
if(pLine->m_nBegin == pointA_ord + 1){
pointA_ord_end = pLine->m_nEnd;
break;
}
pLine = pLine->m_pNext;
}
assert(pointA_ord_end != pointA_ord + 1);
}
}
pLine = m_LineMap_abs[pointB_abs];
if(!m_pMap[pointB_abs * m_max_ord + pointB_ord - 1].m_bExist)
{
while(pLine != NULL)
{
if(pLine->m_nEnd == pointB_ord)
{
pointB_ord_begin = pLine->m_nBegin;
flag = true;
break;
}
pLine = pLine->m_pNext;
}
assert(pointB_ord_begin != pointB_ord);
}
if(!m_pMap[pointB_abs * m_max_ord + pointB_ord + 1].m_bExist)
{
if(flag)
{
pLine = pLine->m_pNext;
assert(pLine != NULL && pointB_ord + 1 == pLine->m_nBegin);
pointB_ord_end = pLine->m_nEnd;
flag = false;
}
else
{
while(pLine != NULL)
{
if(pLine->m_nBegin == pointB_ord + 1)
{
pointB_ord_end = pLine->m_nEnd;
break;
}
pLine = pLine->m_pNext;
}
assert(pointB_ord_end != pointB_ord + 1);
}
}
int point_ord_begin = 0, point_ord_end = 0;
GetCommonRange(pointA_ord_begin, pointA_ord_end, pointB_ord_begin, pointB_ord_end, point_ord_begin, point_ord_end);
if(point_ord_begin == point_ord_end)
return false;
return IsLinkedInSomeOrd(pointA_abs + 1, pointB_abs - 1, point_ord_begin , point_ord_end);
}
bool lMap::CheckLinkedInOrd(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
if(pointA_ord < pointB_ord)
return _CheckLinkedInOrd(pointA_abs, pointA_ord, pointB_abs, pointB_ord);
else
return _CheckLinkedInOrd(pointB_abs, pointB_ord, pointA_abs, pointA_ord);
}
bool lMap::_CheckLinkedInOrd(const int pointA_abs, const int pointA_ord, const int pointB_abs, const int pointB_ord)
{
int pointA_abs_begin = pointA_abs, pointA_abs_end = pointA_abs + 1;
int pointB_abs_begin = pointB_abs, pointB_abs_end = pointB_abs + 1;
bool flag = false;
lLine* pLine = m_LineMap_ord[pointA_ord];
if(!m_pMap[(pointA_abs - 1) * m_max_ord + pointA_ord].m_bExist)
{
while(pLine != NULL)
{
if(pLine->m_nEnd == pointA_abs)
{
pointA_abs_begin = pLine->m_nBegin;
flag = true;
break;
}
pLine = pLine->m_pNext;
}
assert(pointA_abs_begin != pointA_abs);
}
if(!m_pMap[(pointA_abs + 1) * m_max_ord + pointA_ord].m_bExist)
{
if(flag)
{
pLine = pLine->m_pNext;
assert(pLine != NULL && pointA_abs + 1 == pLine->m_nBegin);
pointA_abs_end = pLine->m_nEnd;
flag = false;
}
else
{
while(pLine != NULL)
{
if(pLine->m_nBegin == pointA_abs + 1){
pointA_abs_end = pLine->m_nEnd;
break;
}
pLine = pLine->m_pNext;
}
assert(pointA_abs_end != pointA_abs + 1);
}
}
pLine = m_LineMap_ord[pointB_ord];
if(!m_pMap[(pointB_abs - 1) * m_max_ord + pointB_ord].m_bExist)
{
while(pLine != NULL)
{
if(pLine->m_nEnd == pointB_abs)
{
pointB_abs_begin = pLine->m_nBegin;
flag = true;
break;
}
pLine = pLine->m_pNext;
}
assert(pointB_abs_begin != pointB_abs);
}
if(!m_pMap[(pointB_abs + 1) * m_max_ord + pointB_ord].m_bExist)
{
if(flag)
{
pLine = pLine->m_pNext;
assert(pLine != NULL && pointB_abs + 1 == pLine->m_nBegin);
pointB_abs_end = pLine->m_nEnd;
flag = false;
}
else
{
while(pLine != NULL)
{
if(pLine->m_nBegin == pointB_abs + 1)
{
pointB_abs_end = pLine->m_nEnd;
break;
}
pLine = pLine->m_pNext;
}
assert(pointB_abs_end != pointB_abs + 1);
}
}
int point_abs_begin = 0, point_abs_end = 0;
GetCommonRange(pointA_abs_begin, pointA_abs_end, pointB_abs_begin, pointB_abs_end, point_abs_begin, point_abs_end);
if(point_abs_begin == point_abs_end)
return false;
return IsLinkedInSomeAbs(pointA_ord + 1, pointB_ord - 1, point_abs_begin , point_abs_end);
}
void lMap::GetCommonRange(int rangeA_begin, int rangeA_end, int rangeB_begin, int rangeB_end, int& range_begin, int& range_end)
{
if(rangeA_begin < rangeB_begin)
{
if(rangeA_end <= rangeB_begin)
return;
else if(rangeB_end > rangeA_end)
{
range_begin = rangeB_begin;
range_end = rangeA_end;
}
else
{
range_begin = rangeB_begin;
range_end = rangeB_end;
}
}
else
{
if(rangeB_end == rangeA_begin)
return;
else if(rangeB_end < rangeA_end)
{
range_begin = rangeA_begin;
range_end = rangeB_end;
}
else
{
range_begin = rangeA_begin;
range_end = rangeA_end;
}
}
}
#endif