struct sdLink
{
BYTE a; // a 点
BYTE b; // b 点
BYTE x; // a点的候选数x
BYTE y; // b点的候选数y
bool operator == (const sdLink & oth) const
{
return (a==oth.a && b==oth.b && x==oth.x && y==oth.y);
}
// 路径相同
bool equal (const sdLink & oth) const
{
return (a==oth.a && b==oth.b || a==oth.b && b==oth.a);
}
};
// Forcing Chain 算法2 之数据结构
struct ANFcCell
{
multimap<BYTE, sdLink> mapStrongLinks;
multimap<BYTE, sdLink> mapWeakLinks;
typedef multimap<BYTE, sdLink> FCMap;
typedef pair<BYTE, sdLink> FCPair;
typedef FCMap::iterator FCIT;
typedef pair<FCIT, FCIT> FCII;
public:
void AddStrongLink(const sdLink & l)
{
FCIT it;
FCII ii = mapStrongLinks.equal_range(l.x);
bool bExist = false;
for (it = ii.first; it != ii.second; ++it)
{
if (l == it->second)
{
bExist = true;
break;
}
}
if (!bExist)
{
mapStrongLinks.insert(FCPair(l.x, l));
}
}
void AddWeakLink(const sdLink & l)
{
FCIT it;
FCII ii = mapWeakLinks.equal_range(l.x);
bool bExist = false;
for (it = ii.first; it != ii.second; ++it)
{
if (l == it->second)
{
bExist = true;
break;
}
}
if (!bExist)
{
mapWeakLinks.insert(FCPair(l.x, l));
}
}
void OutPut(int i)
{
if (mapStrongLinks.empty() && mapWeakLinks.empty()) return;
printf("No:%d, ", i);
printf("Strong links num:%d; ", mapStrongLinks.size());
printf("Weak links num:%d/n", mapWeakLinks.size());
for (FCIT it=mapStrongLinks.begin(); it!=mapStrongLinks.end(); ++it)
{
sdLink & l = it->second;
printf("key:%d, l.a:%d, l.b:%d, l.x:%d, l.y:%d/n", it->first, l.a, l.b, l.x, l.y);
}
}
};
bool Sudoku::ANForcingChain()
{
ANFcCell fcell[81];
sdLink link;
_CandiCnt_Map candiLinks;
_CandiCnt_Map::iterator _itCandi;
list<_Point>::iterator _iLstPt;
int i = 0;
// 将每一行,每一列,每个九宫的强,弱链,存储到 fcell中
do {
if (i < 9)
GetLinks(HOUSE_ROW, i, false, 0, candiLinks);
else if (i < 18)
GetLinks(HOUSE_COL, i-9, false, 0, candiLinks);
else
GetLinks(HOUSE_BOX, i-18, false, 0, candiLinks);
for (_itCandi=candiLinks.begin(); _itCandi!=candiLinks.end(); ++_itCandi)
{
link.x = link.y = _itCandi->first;
list<_Point> & lstP = _itCandi->second;
if (lstP.size() == 2) // 强链
{
link.a = lstP.begin()->SN();
link.b = (++lstP.begin())->SN();
fcell[link.a].AddStrongLink(link);
fcell[link.a].AddWeakLink(link);
swap(link.a, link.b);
fcell[link.a].AddStrongLink(link);
fcell[link.a].AddWeakLink(link);
continue;
}
for (_iLstPt = lstP.begin(); _iLstPt != lstP.end(); ++_iLstPt)
{
list<_Point>::iterator iPt = _iLstPt;
for (++iPt; iPt!=lstP.end(); ++iPt)
{
link.a = _iLstPt->SN();
link.b = iPt->SN();
fcell[link.a].AddWeakLink(link);
swap(link.a, link.b);
fcell[link.a].AddWeakLink(link);
}
}
}
++i;
} while (i < 27);
// 上述是针对单候选数(两个数格)的情况,还要看不同候选数(单数格)的强弱链
for (i = 0; i < 81; ++i)
{
ANSudokuCell &cell = m_anCell[i/9][i%9];
if (cell.n == 0) continue;
link.a = link.b = i;
if (cell.n == 2) // 强链
{
link.x = cell.candi[0];
link.y = cell.candi[1];
fcell[link.a].AddStrongLink(link);
fcell[link.a].AddWeakLink(link);
swap(link.x, link.y);
fcell[link.a].AddStrongLink(link);
fcell[link.a].AddWeakLink(link);
continue;
}
for (int p = 0; p < cell.n; ++p)
{
for(int q = p+1; q < cell.n; ++q)
{
link.x = cell.candi[p];
link.y = cell.candi[q];
fcell[link.a].AddWeakLink(link);
swap(link.x, link.y);
fcell[link.a].AddWeakLink(link);
}
}
}
// 打印输出,验证数据整理的是否正确
// for (i = 0; i < 81; ++i)
// {
// fcell[i].OutPut(i);
// }
// printf("size=%d/n", sizeof(fcell));
ANFcCell::FCIT it;
ANFcCell::FCII ii;
for (i = 0; i < 81; ++i)
{
ANSudokuCell &cell = m_anCell[i/9][i%9];
if (cell.n == 0) continue;
list<list<sdLink> > linksN; // 循环查找弱强链所用的容器
ii = fcell[i].mapStrongLinks.equal_range(m_solve[i/9][i%9]);
for (it=ii.first; it!=ii.second; ++it)
{
list<sdLink> lk;
lk.push_back(it->second);
linksN.push_back(lk);
}
while(!linksN.empty())
{
//printf("linksN size=%d/n", linksN.size());
sdLink & head = * linksN.begin()->begin();
// 获取弱链
sdLink & tail = * --linksN.begin()->end();
ii = fcell[tail.b].mapWeakLinks.equal_range(tail.y);
for (it=ii.first; it!=ii.second; ++it)
{
link = it->second;
if ( IsExist(*linksN.begin(), link) ) continue;
// 获取强链
ANFcCell::FCII ii2 = fcell[link.b].mapStrongLinks.equal_range(link.y);
for (ANFcCell::FCIT it2=ii2.first; it2!=ii2.second; ++it2)
{
sdLink & tt = it2->second;
if (link.equal(tt) || IsExist(*linksN.begin(), tt) ) continue;
_Point arrDelPt[20];
int arrCandi[1];
int k = 0;
// 位置相同
if (head.a == tt.b)
{
if (head.x == tt.y) // 且候选数相等
{
arrCandi[0] = tt.y;
k = GetDelPos(_Point(head.a), _Point(tt.b), arrCandi, 1,
arrDelPt);
}
}
else
{
if (head.x == tt.y) // 且候选数相等
{
arrCandi[0] = tt.y;
k = GetDelPos(_Point(head.a), _Point(tt.b), arrCandi, 1,
arrDelPt);
}
else // 候选数不同
{
// same rule (row, col or box)
if (head.a/9 == tt.b/9 || head.a%9 == tt.b%9
|| head.a/9*9+head.a%9 == tt.b/9*9+tt.b%9)
{
ANSudokuCell c2;
c2.n = 1;
c2.candi[0] = tt.y;
if (IsInclude(m_anCell[head.a/9][head.a%9], c2))
{
arrDelPt[k].r = head.a/9;
arrDelPt[k].c = head.a%9;
++k;
}
c2.candi[0] = head.x;
if (IsInclude(m_anCell[tt.b/9][tt.b%9], c2))
{
arrDelPt[k].r = tt.b/9;
arrDelPt[k].c = tt.b%9;
++k;
}
}
}
}
list<sdLink> links = *linksN.begin(); // 测试后的链
links.push_back(link);
links.push_back(it2->second);
if (k <= 0)
{
linksN.push_back(links);
continue;
}
printf("Forcing Chian:/n");
for (list<sdLink>::const_iterator _iL=links.begin(); _iL!=links.end();
++_iL)
{
printf("%d(%d,%d) (%d,%d)%d/n", _iL->x, _iL->a / 9, _iL->a % 9
, _iL->b / 9, _iL->b % 9, _iL->y);
}
printf("Candi:%d Cells to del:", head.x);
for (int j = 0; j < k; ++j)
{
printf("(%d,%d)", arrDelPt[j].r, arrDelPt[j].c);
}
printf("/n");
return true;
}
}
linksN.erase(linksN.begin());
}
}
return false;
}