This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhangshuo1-domain-classific…/StruAndAlgo.h

2563 lines
68 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
//Êý¾Ý½á¹¹ºÍËã·¨À©³ä
//20191212-2054
#include <cstddef>
#include <cmath>
#include <cassert>
#include <type_traits>
#include <limits>
#include <algorithm>
#include <initializer_list>
#include <utility>
#include <tuple>
#include <functional>
#include <iterator>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <stdexcept>
#include <random>
#include <ratio>
//¿â¹ØÁªÐèÇóÎļþ
#include "TypeExtend.h"
//ÆäËû¿âÎļþÉùÃ÷
//tupleÀàÐ͵÷Óú¯Êý·µ»ØÖµÀàÐÍ£¬Ê¹ÓôøcvrefµÄÀàÐÍ´«Èë
template<typename TyFunc, typename TyTup>
struct TupleInvokeReturnType;
//tupleÀàÐ͵÷Óú¯Êý£¬±¾ÖÊÉÏÖ»ÒªÄܱ»getº¯Êý²ð½â¼´¿É£¬ÈôÐèÓÒÖµÔò½«tupleÒÔÓÒÖµ´«Èë
template<typename TyFunc, typename TyTup>
inline typename TupleInvokeReturnType<TyFunc &&, TyTup &&
>::type TupleInvoke(TyFunc &&func, TyTup &&tup);
//дÀàÐͶþ½øÖÆÎļþÀà
//²»Í¬»·¾³µÄÄÚÖÃÀàÐÍ´óС²»Ò»¶¨Ïàͬ£¬Òª±£Ö¤Ê¹ÓôóСÎ޹رäÁ¿
class BinWriteFile;
//¶ÁÀàÐͶþ½øÖÆÎļþÀà
//²»Í¬»·¾³µÄÄÚÖÃÀàÐÍ´óС²»Ò»¶¨Ïàͬ£¬Òª±£Ö¤Ê¹ÓôóСÎ޹رäÁ¿
class BinReadFile;
//¿ìËÙ¼ÆËãÃݴΣ¬×¢Òâ·µ»ØÀàÐͺͻùÀàÐÍÏàͬ
template<typename Ty>
inline constexpr Ty FastPower(Ty base, int power)
{
return power<0 ? 0
: power==0 ? 1
: (power&1)==0 ? FastPower(base*base, power>>1)
: base*FastPower(base*base, power>>1);
}
//ÍÆËã±ÈÀý±íʾ¾«¶È£¬¼´±ÈÀýÀ©´óµ×ÊýµÄ¼¸´ÎÃÝ¿ÉÒÔ´óÓÚµÈÓÚ»ù×¼±ÈÀý
template<typename Ratio, typename BaseRatio,
typename CompareRatio =std::ratio<1>
> inline constexpr typename std::enable_if<
std::ratio_greater_equal<Ratio, CompareRatio>::value, int
>::type RatioPrecision()
{
return 0;
}
template<typename Ratio, typename BaseRatio,
typename CompareRatio =std::ratio<1>
> inline constexpr typename std::enable_if<
!std::ratio_greater_equal<Ratio, CompareRatio>::value, int
>::type RatioPrecision()
{
return RatioPrecision<std::ratio_multiply<Ratio, BaseRatio>,
BaseRatio, CompareRatio>()+1;
}
//Éú³ÉºóÒ»¸ö×éºÏÊý£¬·µ»ØÊÇ·ñµ½Í·
//ÒªÇóË«Ïòµü´úÆ÷£¬¿ÉµÝÔö¡¢ÏàµÈ±È½ÏÖµÀàÐÍ
template<typename TyIt, typename Ty>
bool NextCombination(TyIt st, TyIt ed, Ty rangeSt, Ty rangeEd)
{
auto it= ed, it1= it;
//ÕÒÊýÖµ¿Õ϶
for(; it!=st; --it) {
it1 = it;
-- it1;
if(it==ed) {
if(!(*it1==rangeEd)) {
++ *it1;
break;
}
}
else {
auto value = *it1;
++ value;
if(!(value==*it)) {
*it1 = value;
break;
}
}
}
//ºóÐø×éºÏÊýµÝÔö
bool res = it!=st;
if(it!=ed) {
if(!res)
*it = rangeSt;
else {
it1 = it;
-- it1;
*it = *it1;
++ *it;
}
for(it1=it, ++it; it!=ed; it1=it, ++it) {
*it = *it1;
++ *it;
}
}
return res;
}
//Éú³ÉºóÒ»¸öÅÅÁÐ×éºÏÊý£¬·µ»ØÊÇ·ñµ½Í·
//ÒªÇóË«Ïòµü´úÆ÷£¬¿ÉµÝÔö¡¢ÏàµÈ±È½ÏÖµÀàÐÍ
template<typename TyIt, typename Ty>
bool NextCombinationPermutation(TyIt st, TyIt ed, Ty rangeSt, Ty rangeEd)
{
if(!std::next_permutation(st, ed)) {
if(!NextCombination(st, ed, rangeSt, rangeEd))
return false;
}
return true;
}
//¼ÆÊý¼¯ºÏ½»¼¯£¬ÏßÐÔ¸´ÔÓ¶È£¬ÒªÇóÒÑÅÅÐò
template<typename TyIt1, typename TyIt2,
typename TyLess= GeneralLess<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>,
typename TyEqual= GeneralEqualTo<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>
> inline size_t SetIntersectionCount(TyIt1 st1, TyIt1 ed1, TyIt2 st2, TyIt2 ed2,
TyLess funcLess= TyLess(), TyEqual funcEqual= TyEqual())
{
size_t ret = 0;
while(true) {
if(st1==ed1 || st2==ed2)
break;
//Á½Õß¶¼ÓÐ
if(funcEqual(*st1, *st2)) {
++st1, ++st2;
++ ret;
}
//ǰÕßÓУ¬ºóÕßûÓÐ
else if(funcLess(*st1, *st2)) {
++ st1;
}
//ºóÕßÓУ¬Ç°ÕßûÓÐ
else {
++ st2;
}
}
return ret;
}
//¼ÆÊý¼¯ºÏ²¢¼¯£¬ÏßÐÔ¸´ÔÓ¶È£¬ÒªÇóÒÑÅÅÐò
template<typename TyIt1, typename TyIt2,
typename TyLess= GeneralLess<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>,
typename TyEqual= GeneralEqualTo<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>
> inline size_t SetUnionCount(TyIt1 st1, TyIt1 ed1, TyIt2 st2, TyIt2 ed2,
TyLess funcLess= TyLess(), TyEqual funcEqual= TyEqual())
{
size_t ret = 0;
while(true) {
if(st1==ed1 || st2==ed2) {
//ºóÕßÓÐÊ£Óà
if(st1==ed1)
ret += std::distance(st2, ed2);
//ǰÕßÓÐÊ£Óà
else
ret += std::distance(st1, ed1);
break;
}
//Á½Õß¶¼ÓÐ
if(funcEqual(*st1, *st2)) {
++st1, ++st2;
++ ret;
}
//ǰÕßÓУ¬ºóÕßûÓÐ
else if(funcLess(*st1, *st2)) {
++ st1;
++ ret;
}
//ºóÕßÓУ¬Ç°ÕßûÓÐ
else {
++ st2;
++ ret;
}
}
return ret;
}
//¼ÆÊý¼¯ºÏ²î¼¯£¬ÏßÐÔ¸´ÔÓ¶È£¬ÒªÇóÒÑÅÅÐò
template<typename TyIt1, typename TyIt2,
typename TyLess= GeneralLess<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>,
typename TyEqual= GeneralEqualTo<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>
> inline size_t SetDifferenceCount(TyIt1 st1, TyIt1 ed1, TyIt2 st2, TyIt2 ed2,
TyLess funcLess= TyLess(), TyEqual funcEqual= TyEqual())
{
size_t ret = 0;
while(true) {
if(st1==ed1 || st2==ed2) {
//ºóÕßÓÐÊ£Óà
if(st1==ed1)
;
//ǰÕßÓÐÊ£Óà
else
ret += std::distance(st1, ed1);
break;
}
//Á½Õß¶¼ÓÐ
if(funcEqual(*st1, *st2)) {
++st1, ++st2;
}
//ǰÕßÓУ¬ºóÕßûÓÐ
else if(funcLess(*st1, *st2)) {
++ st1;
++ ret;
}
//ºóÕßÓУ¬Ç°ÕßûÓÐ
else {
++ st2;
}
}
return ret;
}
//¼ÆÊý¼¯ºÏ¶Ô³Æ²î¼¯£¬ÏßÐÔ¸´ÔÓ¶È£¬ÒªÇóÒÑÅÅÐò
template<typename TyIt1, typename TyIt2,
typename TyLess= GeneralLess<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>,
typename TyEqual= GeneralEqualTo<typename IteratorRemoveCVRefDerefType<TyIt1>::type,
typename IteratorRemoveCVRefDerefType<TyIt2>::type>
> inline size_t SetSymmetricDifferenceCount(TyIt1 st1, TyIt1 ed1, TyIt2 st2, TyIt2 ed2,
TyLess funcLess= TyLess(), TyEqual funcEqual= TyEqual())
{
size_t ret = 0;
while(true) {
if(st1==ed1 || st2==ed2) {
//ºóÕßÓÐÊ£Óà
if(st1==ed1)
ret += std::distance(st2, ed2);
//ǰÕßÓÐÊ£Óà
else
ret += std::distance(st1, ed1);
break;
}
//Á½Õß¶¼ÓÐ
if(funcEqual(*st1, *st2)) {
++st1, ++st2;
}
//ǰÕßÓУ¬ºóÕßûÓÐ
else if(funcLess(*st1, *st2)) {
++ st1;
++ ret;
}
//ºóÕßÓУ¬Ç°ÕßûÓÐ
else {
++ st2;
++ ret;
}
}
return ret;
}
//²¢²é¼¯£¬Êý×ÖË÷Òý£¬Êý×é½á¹¹£¬¿ÉÒÔΪ¿ÕÀàÐÍ
template<typename TyData= void>
class IndexDisjointSet
{
private:
//²¢²é¼¯½ÚµãÊý¾Ý½á¹¹
struct Node:
public ValueHolder<TyData>
{
size_t idxPr;//¸¸Ö¸Õë
size_t rank = 0;//ÖÈ£¬Ëã·¨ÓÃ
template<typename ...Ty_S>
Node(size_t idx, Ty_S &&...arg_s):
ValueHolder<TyData>(std::forward<Ty_S>(arg_s)...), idxPr(idx)
{
}
};
private:
std::vector<Node> vec;//Êý¾Ý
public:
//¹¹Ô캯Êý
IndexDisjointSet()
= default;
IndexDisjointSet(const IndexDisjointSet &)
= default;
IndexDisjointSet &operator =(const IndexDisjointSet &)
= default;
IndexDisjointSet(IndexDisjointSet &&)
= default;
IndexDisjointSet &operator =(IndexDisjointSet &&)
= default;
//¶àÊý¾Ý¹¹Ôì
template<typename ...Ty_S>
explicit IndexDisjointSet(size_t size, Ty_S &&...arg_s)
{
Assign(size, std::forward<Ty_S>(arg_s)...);
}
public:
//¶àÊý¾Ý¸³Öµ
template<typename ...Ty_S>
IndexDisjointSet &Assign(size_t size, Ty_S &&...arg_s)
{
for(size_t i=0; i!=size; ++i)
Emplace(std::forward<Ty_S>(arg_s)...);
return *this;
}
//»ñÈ¡Êý¾Ý
typename Node::RefType operator[](size_t idx)
{
return vec[idx];
}
typename Node::ConstRefType operator[](size_t idx) const
{
return vec[idx];
}
//»ñÈ¡´óС
size_t Size() const
{
return vec.size();
}
//Çå¿Õ
void Clear()
{
vec.clear();
}
//Ìí¼Óµã£¬·µ»Ø¸ù
template<typename ...Ty_S>
size_t Emplace(Ty_S &&...arg_s)
{
size_t root = vec.size();
vec.emplace_back(root, std::forward<Ty_S>(arg_s)...);
return root;
}
//Ìí¼ÓµãͬʱÁ¬½Ó£¬·µ»Ø¸ù
template<typename ...Ty_S>
size_t EmplaceUnion(size_t idx, Ty_S &&...arg_s)
{
size_t root = vec.size();
vec.emplace_back(root, std::forward<Ty_S>(arg_s)...);
return Union(root, idx);
}
//ÕÒ¸ù½Úµã
size_t FindRoot(size_t idx)
{
if(vec[idx].idxPr!=idx)
//ÕÒµÄͬʱÁ¬½Óµ½¸ù
vec[idx].idxPr = FindRoot(vec[idx].idxPr);
return vec[idx].idxPr;
}
//ºÏ²¢¼¯ºÏ£¬·µ»Ø¸ù
size_t Union(size_t idx1, size_t idx2)
{
size_t root1 = FindRoot(idx1), root2 = FindRoot(idx2);
if(vec[root1].rank<=vec[root2].rank) {
//1Á¬µ½2ÉÏ
vec[root1].idxPr = root2;
if(vec[root1].rank==vec[root2].rank)
++ vec[root2].rank;
return root2;
}
else {
//2Á¬µ½1ÉÏ
vec[root2].idxPr = root1;
return root1;
}
}
//ÈÝÆ÷½Ó¿Ú
void Reserve(size_t size)
{
vec.reserve(size);
}
size_t Capacity() const
{
return vec.capacity();
}
void ShinkToFit()
{
return vec.shink_to_fit();
}
};
template<typename TyKey, typename TyValue= void, typename TyCom= std::less<TyKey>>
class MapDisjointSetNode;
//Ê÷Ðβ¢²é¼¯ÀàÐͼòд£¬Ö§³ÖÁ¬½ÓºÍÌí¼Ó»ìÓ㬲¢²é¼¯±êǩΪÊ÷µü´úÆ÷
template<typename TyKey, typename TyValue= void, typename TyCom= std::less<TyKey>>
using MapDisjointSet = std::map<TyKey, MapDisjointSetNode<TyKey, TyValue, TyCom>, TyCom>;
//Ê÷Ðβ¢²é¼¯£¬½Úµã½á¹¹£¬½«Æä¸³¸ømapÄ£°åÀàÐÍʹÓÃ
template<typename TyKey, typename TyValue, typename TyCom>
class MapDisjointSetNode:
private ValueHolder<TyValue>
{
template<typename TyIt>
friend TyIt MapDisjointSetFindRoot(TyIt it);
template<typename TyIt>
friend TyIt MapDisjointSetUnion(TyIt it1, TyIt it2);
private:
typename MapDisjointSet<TyKey, TyValue, TyCom>::iterator itPr;//´æ´¢Ö¸Õë
size_t rank = 0;//ÖÈ£¬Ëã·¨ÓÃ
bool bRoot = true;//¼Ç¼ÊÇ·ñΪ¸ù£¬Îª¸ùʱ²»Ðè±£Ö¤Ö¸ÕëÓÐЧ
public:
//¹¹Ô캯Êý
template<typename ...Ty_S>
MapDisjointSetNode(Ty_S &&...arg_s):
ValueHolder<TyValue>(std::forward<Ty_S>(arg_s)...)
{
}
//ÒýÓÃԭʼÊý¾Ý
typename ValueHolder<TyValue>::RefType Get()
{
return this->hold;
}
typename ValueHolder<TyValue>::ConstRefType Get() const
{
return this->hold;
}
};
//Ê÷Ðβ¢²é¼¯¾²Ì¬Ëã·¨£¬ÕÒ¸ù½Úµã£¬½ÓÊÜÖ¸Õë»òµü´úÆ÷
template<typename TyIt>
inline TyIt MapDisjointSetFindRoot(TyIt it)
{
if(it->second.bRoot)
return it;
else {
it->second.itPr = MapDisjointSetFindRoot(it->second.itPr);
return it->second.itPr;
}
}
//Ê÷Ðβ¢²é¼¯¾²Ì¬Ëã·¨£¬ºÏ²¢¼¯ºÏ£¬½ÓÊÜÖ¸Õë»òµü´úÆ÷£¬·µ»Ø¸ù
template<typename TyIt>
inline TyIt MapDisjointSetUnion(TyIt it1, TyIt it2)
{
TyIt root1= MapDisjointSetFindRoot(it1), root2= MapDisjointSetFindRoot(it2);
if(root1==root2)
return root1;
if(root1->second.rank<=root2->second.rank) {
//1Á¬µ½2ÉÏ
root1->second.itPr = root2;
root1->second.bRoot = false;
if(root1->second.rank==root2->second.rank)
++ root2->second.rank;
return root2;
}
else {
//2Á¬µ½1ÉÏ
root2->second.itPr = root1;
root2->second.bRoot = false;
return root1;
}
}
template<typename TyKey, typename TyValue= void,
typename TyHash= std::hash<TyKey>, typename TyEqual= std::equal_to<TyKey>
> class UnordMapDisjointSetNode;
//¹þÏ£²¢²é¼¯ÀàÐͼòд£¬Ö§³ÖÁ¬½ÓºÍÌí¼Ó»ìÓ㬲¢²é¼¯±êǩΪÄÚÈÝpairÖ¸Õë
template<typename TyKey, typename TyValue= void,
typename TyHash= std::hash<TyKey>, typename TyEqual= std::equal_to<TyKey>
> using UnordMapDisjointSet = std::unordered_map<TyKey,
UnordMapDisjointSetNode<TyKey, TyValue, TyHash, TyEqual>, TyHash, TyEqual>;
//¹þÏ£²¢²é¼¯£¬½Úµã½á¹¹£¬½«Æä¸³¸øunordered_mapÄ£°åÀàÐÍʹÓÃ
template<typename TyKey, typename TyValue, typename TyHash, typename TyEqual>
class UnordMapDisjointSetNode:
private ValueHolder<TyValue>
{
template<typename TyIt>
friend auto UnordMapDisjointSetFindRoot(TyIt it)-> decltype(&*it);
template<typename TyIt>
friend auto UnordMapDisjointSetUnion(TyIt it1, TyIt it2)-> decltype(&*it1);
private:
typename UnordMapDisjointSet<TyKey, TyValue, TyHash, TyEqual>::pointer pPr= nullptr;//´æ´¢Ö¸Õë
size_t rank = 0;//ÖÈ£¬Ëã·¨ÓÃ
bool bRoot = true;//¼Ç¼ÊÇ·ñΪ¸ù£¬Îª¸ùʱ²»Ðè±£Ö¤Ö¸ÕëÓÐЧ
public:
//¹¹Ô캯Êý
template<typename ...Ty_S>
UnordMapDisjointSetNode(Ty_S &&...arg_s):
ValueHolder<TyValue>(std::forward<Ty_S>(arg_s)...)
{
}
//ÒýÓÃԭʼÊý¾Ý
typename ValueHolder<TyValue>::RefType Get()
{
return this->hold;
}
typename ValueHolder<TyValue>::ConstRefType Get() const
{
return this->hold;
}
};
//¹þÏ£²¢²é¼¯¾²Ì¬Ëã·¨£¬ÕÒ¸ù½Úµã£¬½ÓÊÜÖ¸Õë»òµü´úÆ÷
template<typename TyIt>
inline auto UnordMapDisjointSetFindRoot(TyIt it)-> decltype(&*it)
{
if(it->second.bRoot)
return &*it;
else {
auto itRes = UnordMapDisjointSetFindRoot(it->second.pPr);
it->second.pPr = &*itRes;
return it->second.pPr;
}
}
//¹þÏ£²¢²é¼¯¾²Ì¬Ëã·¨£¬ºÏ²¢¼¯ºÏ£¬½ÓÊÜÖ¸Õë»òµü´úÆ÷£¬·µ»Ø¸ù
template<typename TyIt>
inline auto UnordMapDisjointSetUnion(TyIt it1, TyIt it2)-> decltype(&*it1)
{
auto root1= UnordMapDisjointSetFindRoot(it1),
root2= UnordMapDisjointSetFindRoot(it2);
if(root1==root2)
return root1;
if(root1->second.rank<=root2->second.rank) {
//1Á¬µ½2ÉÏ
root1->second.pPr = root2;
root1->second.bRoot = false;
if(root1->second.rank==root2->second.rank)
++ root2->second.rank;
return root2;
}
else {
//2Á¬µ½1ÉÏ
root2->second.pPr = root1;
root2->second.bRoot = false;
return root1;
}
}
//Æ¥ÅäÊ÷ÄÚ²¿½ÚµãÀàÐÍ£¬Æ½ºâÊ÷ʵÏÖ
template<typename TyMatch, typename TyData>
struct _TrieTreeNode
{
using RetDataType = TyData *;
using ConstRetDataType = const TyData *;
constexpr static bool bIsVoid = false;
public:
TyData *pData = nullptr;
std::map<TyMatch, _TrieTreeNode<TyMatch, TyData>> mapCh;//×ÓÊ÷
public:
_TrieTreeNode()
= default;
~_TrieTreeNode()
{
delete pData;
}
//¿½±´º¯Êý
_TrieTreeNode(const _TrieTreeNode &other)
{
operator =(other);
}
_TrieTreeNode &operator =(const _TrieTreeNode &other)
{
if(this!=&other) {
//Èô¶Ô·½ÓÐÊý¾Ý
if(other.pData) {
if(pData)
*pData = *other.pData;
else
Construct(other.data);
}
//Èô¶Ô·½Ã»Êý¾Ý
else {
if(pData) {
delete pData;
pData = nullptr;
}
}
//¿½±´ÆäËûÊý¾Ý
mapCh = other.mapCh;
}
return *this;
}
//¹¹ÔìÊý¾Ý
template<typename ...Ty_S>
void Construct(Ty_S &&...arg_s)
{
assert(pData==nullptr);
pData = new TyData(std::forward<Ty_S>(arg_s)...);
}
//Çå³ýÊý¾Ý
void Clear()
{
delete pData;
pData = nullptr;
mapCh.clear();
}
//»ñÈ¡Êý¾ÝÖ¸Õë
static RetDataType GetData(_TrieTreeNode *pt)
{
if(pt==nullptr)
return nullptr;
else
return pt->pData;
}
static ConstRetDataType GetData(const _TrieTreeNode *pt)
{
return GetData((_TrieTreeNode *)pt);
}
};
template<typename TyMatch>
struct _TrieTreeNode<TyMatch, void>
{
using RetDataType = bool;
using ConstRetDataType = bool;
constexpr static bool bIsVoid = true;
public:
bool bData = false;//ÊÇ·ñÓÐÊý¾Ý
std::map<TyMatch, _TrieTreeNode<TyMatch, void>> mapCh;//×ÓÊ÷
public:
//¹¹ÔìÊý¾Ý
void Construct()
{
bData = true;
}
//Çå³ýÊý¾Ý
void Clear()
{
bData = false;
mapCh.clear();
}
//»ñÈ¡Êý¾Ý±êÇ©
static ConstRetDataType GetData(const _TrieTreeNode *pt)
{
if(pt==nullptr)
return false;
else
return pt->bData;
}
};
//Æ¥ÅäÊ÷ÄÚ²¿½ÚµãÀàÐÍ£¬¹þÏ£±íʵÏÖ
template<typename TyMatch, typename TyData>
struct _UnordTrieTreeNode
{
using RetDataType = TyData *;
using ConstRetDataType = const TyData *;
constexpr static bool bIsVoid = false;
public:
TyData *pData = nullptr;
std::unordered_map<TyMatch, _UnordTrieTreeNode<TyMatch, TyData>> mapCh;//×ÓÊ÷
public:
_UnordTrieTreeNode()
= default;
~_UnordTrieTreeNode()
{
delete pData;
}
//¿½±´º¯Êý
_UnordTrieTreeNode(const _UnordTrieTreeNode &other)
{
operator =(other);
}
_UnordTrieTreeNode &operator =(const _UnordTrieTreeNode &other)
{
if(this!=&other) {
//Èô¶Ô·½ÓÐÊý¾Ý
if(other.pData) {
if(pData)
*pData = *other.pData;
else
Construct(other.data);
}
//Èô¶Ô·½Ã»Êý¾Ý
else {
if(pData) {
delete pData;
pData = nullptr;
}
}
//¿½±´ÆäËûÊý¾Ý
mapCh = other.mapCh;
}
return *this;
}
//¹¹ÔìÊý¾Ý
template<typename ...Ty_S>
void Construct(Ty_S &&...arg_s)
{
assert(pData==nullptr);
pData = new TyData(std::forward<Ty_S>(arg_s)...);
}
//Çå³ýÊý¾Ý
void Clear()
{
delete pData;
pData = nullptr;
mapCh.clear();
}
//»ñÈ¡Êý¾ÝÖ¸Õë
static RetDataType GetData(_UnordTrieTreeNode *pt)
{
if(pt==nullptr)
return nullptr;
else
return pt->pData;
}
static ConstRetDataType GetData(const _UnordTrieTreeNode *pt)
{
return GetData((_UnordTrieTreeNode *)pt);
}
};
template<typename TyMatch>
struct _UnordTrieTreeNode<TyMatch, void>
{
using RetDataType = bool;
using ConstRetDataType = bool;
constexpr static bool bIsVoid = true;
public:
bool bData = false;//ÊÇ·ñÓÐÊý¾Ý
std::unordered_map<TyMatch, _UnordTrieTreeNode<TyMatch, void>> mapCh;//×ÓÊ÷
public:
//¹¹ÔìÊý¾Ý
void Construct()
{
bData = true;
}
//Çå³ýÊý¾Ý
void Clear()
{
bData = false;
mapCh.clear();
}
//»ñÈ¡Êý¾Ý±êÇ©
static ConstRetDataType GetData(const _UnordTrieTreeNode *pt)
{
if(pt==nullptr)
return false;
else
return pt->bData;
}
};
//binfile½Ó¿Ú¸¨Öú£¬¿ÉÒÔ¼æÈݺóÃæµÄAcMachineNode
template<typename TyNode>
inline typename std::enable_if<!TyNode::bIsVoid, void
>::type _BinWriteTrieOrAcNodeAssist(BinWriteFile &bwf, TyNode &node)
{
uint8_t bData = node.pData!=nullptr;
bwf <<bData;
if(bData)
bwf <<*node.pData;
bwf <<node.mapCh;
}
template<typename TyNode>
inline typename std::enable_if<TyNode::bIsVoid, void
>::type _BinWriteTrieOrAcNodeAssist(BinWriteFile &bwf, TyNode &node)
{
bwf <<(uint8_t)node.bData;
bwf <<node.mapCh;
}
template<typename TyNode>
inline typename std::enable_if<!TyNode::bIsVoid, void
>::type _BinReadTrieOrAcNodeAssist(BinReadFile &brf, TyNode &node)
{
uint8_t bData;
brf >>bData;
//Èô¶Ô·½ÓÐÊý¾Ý
if(bData) {
if(node.pData==nullptr)
node.Construct();
brf >>*node.pData;
}
//Èô¶Ô·½Ã»Êý¾Ý
else {
if(node.pData) {
delete node.pData;
node.pData = nullptr;
}
}
brf >>node.mapCh;
}
template<typename TyNode>
inline typename std::enable_if<TyNode::bIsVoid, void
>::type _BinReadTrieOrAcNodeAssist(BinReadFile &brf, TyNode &node)
{
uint8_t bData;
brf >>bData;
node.bData = bData;
brf >>node.mapCh;
}
//binfile½Ó¿Ú
template<typename TyMatch, typename TyData>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _TrieTreeNode<TyMatch, TyData> &node)
{
_BinWriteTrieOrAcNodeAssist(bwf, node);
return bwf;
}
template<typename TyMatch, typename TyData>
inline BinReadFile &operator >>(BinReadFile &brf, _TrieTreeNode<TyMatch, TyData> &node)
{
_BinReadTrieOrAcNodeAssist(brf, node);
return brf;
}
template<typename TyMatch, typename TyData>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _UnordTrieTreeNode<TyMatch, TyData> &node)
{
_BinWriteTrieOrAcNodeAssist(bwf, node);
return bwf;
}
template<typename TyMatch, typename TyData>
inline BinReadFile &operator >>(BinReadFile &brf, _UnordTrieTreeNode<TyMatch, TyData> &node)
{
_BinReadTrieOrAcNodeAssist(brf, node);
return brf;
}
template<typename TyNode>
class _TrieTreeTemplate;
//Ê÷ÐÎÆ¥Åä½á¹¹ÉÏÏÂÎÄ
template<typename TyNode, typename TyIt>
struct _TrieContextTemplate
{
bool bFirst = true;//¼Ç¼Ê×´ÎÆ¥Åä
TyNode *pt;//Ê÷½ÚµãÖ¸Õë
TyIt it;//Æ¥Åä´®Ö¸Õë
};
template<typename TyNode, typename TyIt>
inline _TrieContextTemplate<TyNode, TyIt> MakeTrieContext(const _TrieTreeTemplate<TyNode> &, TyIt)
{
return _TrieContextTemplate<TyNode, TyIt>();
}
//Ê÷×´´®Æ¥Åä½á¹¹£¬Ö§³ÖvoidÊý¾Ý
template<typename TyNode>
class _TrieTreeTemplate
{
template<typename TyNode2>
friend BinWriteFile &operator <<(BinWriteFile &bwf, const _TrieTreeTemplate<TyNode2> &trie);
template<typename TyNode2>
friend BinReadFile &operator >>(BinReadFile &brf, _TrieTreeTemplate<TyNode2> &trie);
public:
//¸¨ÖúÀàÐÍ
using NodeType = TyNode;
using RetDataType = typename NodeType::RetDataType;
using ConstRetDataType = typename NodeType::ConstRetDataType;
private:
NodeType *pRoot;//Ê÷¸ù½Úµã
public:
//Î忽±´
_TrieTreeTemplate():
pRoot(new NodeType)
{
}
~_TrieTreeTemplate()
{
delete pRoot;
}
_TrieTreeTemplate(const _TrieTreeTemplate &other):
_TrieTreeTemplate()
{
operator =(other);
}
_TrieTreeTemplate(_TrieTreeTemplate &&other):
_TrieTreeTemplate()
{
operator =(std::move(other));
}
_TrieTreeTemplate &operator =(const _TrieTreeTemplate &other)
{
if(this!=&other) {
*pRoot = *other.pRoot;
}
return *this;
}
_TrieTreeTemplate &operator =(_TrieTreeTemplate &&other)
{
if(this!=&other) {
std::swap(pRoot, other.pRoot);
}
return *this;
}
private:
//Õҽڵ㸨Öúº¯Êý£¬¿Õ´®¿ÉÒÔÆ¥Åä¿ÕÆ¥Å䣬pNode·µ»ØÆ¥ÅäµÄ½Úµã»ò¿Õ
//itSt·µ»ØÆ¥ÅäµÄβºó£¬bShortÕÒµ½¼´½áÊø£¬bBlankÔÊÐí¿ÕÆ¥Å䣬bAdd²éÕÒʱÏòºóÌí¼Ó
template<typename TyIt>
static void FindAssist(NodeType *&pNode, TyIt &itSt, TyIt itEd,
bool bShort, bool bBlank, bool bAdd)
{
//ÅжϿÕÖ¸Õë
if(pNode==nullptr)
return;
//ÔÊÐíΪ¿ÕʱµÄ´¦Àí
if(bBlank) {
//Ìáǰ½áÊøÇÒÆ¥Å䣬»òÒѾ­Ã»ÓÐÆ¥ÅäºóÐø£¬Ôò·µ»Ø³õʼ½Úµã
if((bShort && NodeType::GetData(pNode)) || itSt==itEd)
return;
}
//ÈôÌáǰ½áÊøÊ§°ÜÇÒûÓкóÐøÆ¥Å䣬ÔòÈÏΪÕÒ²»µ½
if(itSt==itEd) {
pNode = nullptr;
}
//Ö÷Ñ­»·
while(itSt!=itEd) {//µü´úÆ÷½áÊøÔòÌø³ö£¬´Ëʱ·µ»ØÖµÎªÕÒµ½µÄ½Úµã
//¸ù¾ÝÌí¼ÓÇé¿öÏòºóµü´ú
if(bAdd)
pNode = &pNode->mapCh[*itSt];
else {
auto itPr = pNode->mapCh.find(*itSt);
//²»Ìí¼ÓÇÒÕÒ²»µ½¾Í·µ»Ø¿Õ
if(itPr==pNode->mapCh.end()) {
pNode = nullptr;
break;
}
pNode = &itPr->second;
}
++ itSt;
//ÅÐÌáǰ½áÊø£¬´Ëʱµü´úÆ÷ÒѳÉΪβºó
if(bShort && NodeType::GetData(pNode))
break;
}
}
public:
//Ìí¼ÓÆ¥Å乿Ôò
template<typename TyIt, typename ...Ty_S>
bool EmplaceRule(TyIt itSt, TyIt itEd, Ty_S &&...arg_s)
{
NodeType *pNode = pRoot;
FindAssist(pNode, itSt, itEd, false, true, true);
if(NodeType::GetData(pNode))
return false;
pNode->Construct(std::forward<Ty_S>(arg_s)...);
return true;
}
//Çå³ý½Úµã
void Clear()
{
pRoot->Clear();
}
//Æ¥ÅäÍêÕû´®£¬Êý¾ÝÀàÐÍ·µ»ØÖ¸Õ룬¿ÕÀàÐÍ·µ»Ø²¼¶û
//ÕÒ²»µ½·µ»Ø¿ÕÖ¸Õë»ò·ñ£¬ÈôÕÒµ½Ôòµü´úÆ÷Ϊβºó£¬ÈôδÕÒµ½µü´úÆ÷´æÆ¥Åä²»µ½µÄµÚÒ»¸öλÖÃ
template<typename TyIt>
std::pair<TyIt, RetDataType> Match(TyIt itSt, TyIt itEd)
{
NodeType *pNode = pRoot;
FindAssist(pNode, itSt, itEd, false, true, false);
return std::make_pair(itSt, NodeType::GetData(pNode));
}
template<typename TyIt>
std::pair<TyIt, ConstRetDataType> Match(TyIt itSt, TyIt itEd) const
{
return ((_TrieTreeTemplate *)this)->Match(itSt, itEd);
}
//µü´úËÑË÷´®£¬Êý¾ÝÀàÐÍ·µ»ØÖ¸Õ룬¿ÕÀàÐÍ·µ»Ø²¼¶û
//ÕÒ²»µ½·µ»Ø¿ÕÖ¸Õ룬ÈôÕÒµ½Ôòµü´úÆ÷Ϊβºó£¬ÈôδÕÒµ½µü´úÆ÷´æÆ¥Åä²»µ½µÄµÚÒ»¸öλÖÃ
//ctx³õʼ¸³Ä¬ÈϹ¹Ô죬֮ºóÁ¬ÐøÊ¹ÓôË×÷ΪÖмä¼þ
template<typename TyIt, typename TyCtx= _TrieContextTemplate<TyNode, TyIt>>
typename std::enable_if<IsRemoveCVRefSame<_TrieContextTemplate<TyNode, TyIt>,
TyCtx>::value, std::pair<TyIt, RetDataType>
>::type Search(TyIt itSt, TyIt itEd, TyCtx &&ctx= TyCtx())
{
bool bBlank = false;
if(ctx.bFirst) {
ctx.bFirst = false;
ctx.pt = pRoot;
ctx.it = itSt;
bBlank = true;//µÚÒ»´Î¿ÉÒÔÆ¥Åä¿Õ£¬Îª±£Ö¤ÍƽøºóÐø²»ÐÐ
}
FindAssist(ctx.pt, ctx.it, itEd, true, bBlank, false);
return std::make_pair(ctx.it, NodeType::GetData(ctx.pt));
}
template<typename TyIt, typename TyCtx= _TrieContextTemplate<TyNode, TyIt>>
typename std::enable_if<IsRemoveCVRefSame<_TrieContextTemplate<TyNode, TyIt>,
TyCtx>::value, std::pair<TyIt, ConstRetDataType>
>::type Search(TyIt itSt, TyIt itEd, TyCtx &&ctx= TyCtx()) const
{
return ((_TrieTreeTemplate *)this)->Search(itSt, itEd, ctx);
}
//Æ¥Åä×´®£¬Êý¾ÝÀàÐÍ·µ»ØÖ¸Õ룬¿ÕÀàÐÍ·µ»Ø²¼¶û
//ÕÒ²»µ½·µ»Ø¿ÕÖ¸Õ룬ÈôÕÒµ½Ôòµü´úÆ÷Ϊβºó£¬ÈôδÕÒµ½µü´úÆ÷´æÆ¥Åä²»µ½µÄµÚÒ»¸öλÖÃ
template<typename TyIt>
std::pair<TyIt, RetDataType> SearchLong(TyIt itSt, TyIt itEd)
{
_TrieContextTemplate<TyNode, TyIt> ctx;
//Ê×ÏȲéÕÒÒ»´Î
auto ret = Search(itSt, itEd, ctx);
//ÈôÕҵõ½Ôò¼ÌÐøÕÒ
if(ret.second) {
while(true) {
auto tmp = Search(itSt, itEd, ctx);
if(!tmp.second)
break;
ret = tmp;
}
}
return ret;
}
template<typename TyIt>
std::pair<TyIt, ConstRetDataType> SearchLong(TyIt itSt, TyIt itEd) const
{
return ((_TrieTreeTemplate *)this)->SearchLong(itSt, itEd);
}
//ÕÒµ½µÚÒ»¸ö
template<typename TyIt>
RetDataType Judge(TyIt itSt, TyIt itEd)
{
return Search(itSt, itEd).second;
}
template<typename TyIt>
ConstRetDataType Judge(TyIt itSt, TyIt itEd) const
{
return ((_TrieTreeTemplate *)this)->Judge(itSt, itEd);
}
//¼ÆÊýÕÒµ½´ÎÊý
template<typename TyIt>
size_t Count(TyIt itSt, TyIt itEd) const
{
_TrieContextTemplate<TyNode, TyIt> ctx;
size_t cnt = 0;
for(; ; ++cnt) {
if(!Search(itSt, itEd, ctx).second)
break;
}
return cnt;
}
};
//binfile½Ó¿Ú
template<typename TyNode>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _TrieTreeTemplate<TyNode> &trie)
{
return bwf <<*trie.pRoot;
}
template<typename TyNode>
inline BinReadFile &operator >>(BinReadFile &brf, _TrieTreeTemplate<TyNode> &trie)
{
return brf >>*trie.pRoot;
}
//¶¨ÒåËÑË÷Ê÷µÄƽºâÊ÷ʵÏÖ
template<typename TyMatch, typename TyData= void>
using TrieTree = _TrieTreeTemplate<_TrieTreeNode<TyMatch, TyData>>;
template<typename TyMatch, typename TyData, typename TyIt>
using TrieContext = _TrieContextTemplate<_TrieTreeNode<TyMatch, TyData>, TyIt>;
//¶¨ÒåËÑË÷Ê÷µÄ¹þÏ£±íʵÏÖ
template<typename TyMatch, typename TyData= void>
using UnordTrieTree = _TrieTreeTemplate<_UnordTrieTreeNode<TyMatch, TyData>>;
template<typename TyMatch, typename TyData, typename TyIt>
using UnordTrieContext = _TrieContextTemplate<_UnordTrieTreeNode<TyMatch, TyData>, TyIt>;
//KMPËÑË÷ÀàÉÏÏÂÎÄ
template<typename TyItT, typename TyItP>
struct KmpContext
{
ptrdiff_t cnt = -1;//ÒÑÆ¥ÅäµÄ¸öÊý£¬¸ºÊý±íʾδ³õʼ»¯
TyItP itSub;//Æ¥Åäģʽ´®µÄµü´úλÖÃ
TyItT it;//Îı¾´®Î»ÖÃ
TyItT itTFlag;//Îı¾´®¶ÔÆë¿ªÊ¼Î»ÖÃ
};
template<typename TyItT, typename TyItP>
inline KmpContext<TyItT, TyItP> MakeKmpContext(TyItT, TyItP)
{
return KmpContext<TyItT, TyItP>();
}
//KMPËÑË÷Àà
class KmpSearcher
{
std::vector<ptrdiff_t> vecSub;//¼Ç¼ÓÒÒÆµÄ³¤¶È£¬µÚiÏî¼Ç¼µÄÊÇÒÑÆ¥Åäi+1¸öºóµÄÒÆ¶¯³¤¶È£¬¼´Ï±êiλÖÃ
public:
KmpSearcher()
= default;
template<typename TyIt>
KmpSearcher(TyIt itSt, TyIt itEd)
{
Assign(itSt, itEd);
}
public:
//¸³Öµº¯Êý
template<typename TyIt>
KmpSearcher &Assign(TyIt itSt, TyIt itEd)
{
vecSub.resize(std::distance(itSt, itEd));
if(vecSub.empty())
return *this;
vecSub[1-1] = 1;//ÈôÒÑÆ¥Åä1¸ö£¬ÔòÓ¦¸ÃÓÒÒÆ1
ptrdiff_t cnt = 0;//ÒÑÆ¥ÅäµÄ¸öÊý
auto itSub = itSt;//Æ¥Åäģʽ´®µÄµü´úλÖÃ
ptrdiff_t locate = 1;//µ±Ç°¶ÁÈ¡´®µÄϱê
//Ö÷ÌåÑ­»·
for(++itSt; itSt!=itEd; ++itSt, ++locate) {
while(cnt!=0 && *itSt!=*itSub) {
//¸Ä±ä¶ÔÆëλÖúͳ¤¶È
std::advance(itSub, -vecSub[cnt-1]);
cnt -= vecSub[cnt-1];
}
if(*itSt==*itSub)
++ cnt, ++itSub;
vecSub[locate] = (locate+1-cnt);
}
return *this;
}
//ËÑË÷º¯Êý£¬Ö§³ÖΪ¿ÕÆ¥Å䣬ÈôÕÒµ½µü´úÆ÷Ϊָ¶¨´®£¬Î´ÕÒµ½µü´úÆ÷¾ùΪ´®Î²ºó
template<typename TyItT, typename TyItP, typename TyCtx= KmpContext<TyItT, TyItP>>
typename std::enable_if<IsRemoveCVRefSame<KmpContext<TyItT, TyItP>, TyCtx>::value,
std::pair<TyItT, TyItT>
>::type Search(TyItT itTSt, TyItT itTEd, TyItP itPSt, TyItP itPEd,
TyCtx &&ctx= TyCtx()) const
{
assert(std::distance(itPSt, itPEd)==vecSub.size());
//³õʼ»¯
if(ctx.cnt<0) {
ctx.cnt = 0;
ctx.it = itTSt;
ctx.itSub = itPSt;
ctx.itTFlag = itTSt;
}
//ÅжϿմ®Æ¥Åä
if(itPSt==itPEd) {
auto ret = std::make_pair(ctx.itTFlag, ctx.it);
++ ctx.it, ctx.itTFlag;
return ret;
}
//Ö÷ÌåÑ­»·
for(; ctx.it!=itTEd; ++ctx.it) {
while(ctx.cnt!=0 && *ctx.it!=*ctx.itSub) {
//¸Ä±ä¶ÔÆëλÖúͳ¤¶È
std::advance(ctx.itSub, -vecSub[ctx.cnt-1]);
std::advance(ctx.itTFlag, vecSub[ctx.cnt-1]);
ctx.cnt -= vecSub[ctx.cnt-1];
}
if(*ctx.it==*ctx.itSub) {
++ ctx.cnt, ++ctx.itSub;
if(ctx.cnt==vecSub.size()) {
//ÏÂÒ»¸öÑ­»·Á¿
++ ctx.it;
auto ret = std::make_pair(ctx.itTFlag, ctx.it);
//¸Ä±ä¶ÔÆëλÖúͳ¤¶È
std::advance(ctx.itSub, -vecSub[ctx.cnt-1]);
std::advance(ctx.itTFlag, vecSub[ctx.cnt-1]);
ctx.cnt -= vecSub[ctx.cnt-1];
return ret;
}
}
else
++ ctx.itTFlag;
}
return std::make_pair(itTEd, itTEd);
}
//ÅжÏÊÇ·ñÕÒµ½
template<typename TyItT, typename TyItP>
bool Judge(TyItT itTSt, TyItT itTEd, TyItP itPSt, TyItP itPEd) const
{
return Search(itTSt, itTEd, itPSt, itPEd).first!=itTEd;
}
//¼ÆÊýÕÒµ½´ÎÊý
template<typename TyItT, typename TyItP>
size_t Conut(TyItT itTSt, TyItT itTEd, TyItP itPSt, TyItP itPEd) const
{
KmpContext<TyItT, TyItP> ctx;
size_t cnt = 0;
for(; ; ++cnt) {
if(Search(itTSt, itTEd, itPSt, itPEd, ctx).first==itTEd)
break;
}
return cnt;
}
};
//AC×Ô¶¯»úÄÚ²¿½ÚµãÀàÐÍ£¬Æ½ºâÊ÷ʵÏÖ
template<typename TyMatch, typename TyData>
struct _AcMachineNode
{
using RetDataType = TyData *;
using ConstRetDataType = const TyData *;
constexpr static bool bIsVoid = false;
public:
TyData *pData = nullptr;
std::map<TyMatch, _AcMachineNode> mapCh;//×ÓÊ÷
size_t layer = 0;//µ±Ç°²ã
_AcMachineNode *pBack = nullptr;//»ØËݽڵãÖ¸Õë
_AcMachineNode *pFind = nullptr;//²éÕÒÓÐЧ½ÚµãÖ¸Õë
public:
_AcMachineNode()
= default;
~_AcMachineNode()
{
delete pData;
}
//¿½±´º¯Êý£¬¿½±´ºóÐèÒªÖØÐ¹¹ÔìÖ¸Õë
_AcMachineNode(const _AcMachineNode &other)
{
operator =(other);
}
_AcMachineNode &operator =(const _AcMachineNode &other)
{
if(this!=&other) {
mapCh = other.mapCh;
//Èô¶Ô·½ÓÐÊý¾Ý
if(other.pData) {
if(pData)
*pData = *other.pData;
else
Construct(other.data);
}
//Èô¶Ô·½Ã»Êý¾Ý
else {
if(pData) {
delete pData;
pData = nullptr;
}
}
//¿½±´ÆäËûÊý¾Ý
mapCh = other.mapCh;
layer = other.layer;
pBack = nullptr;
pFind = nullptr;
}
return *this;
}
//¹¹ÔìÊý¾Ý
template<typename ...Ty_S>
void Construct(Ty_S &&...arg_s)
{
assert(pData==nullptr);
pData = new TyData(std::forward<Ty_S>(arg_s)...);
}
//Çå³ýÊý¾Ý
void Clear()
{
delete pData;
pData = nullptr;
mapCh.clear();
}
//»ñÈ¡Êý¾ÝÖ¸Õë
static RetDataType GetData(_AcMachineNode *pt)
{
if(pt==nullptr)
return nullptr;
else
return pt->pData;
}
static ConstRetDataType GetData(const _AcMachineNode *pt)
{
return GetData((_AcMachineNode *)pt);
}
};
template<typename TyMatch>
struct _AcMachineNode<TyMatch, void>
{
using RetDataType = bool;
using ConstRetDataType = bool;
constexpr static bool bIsVoid = true;
public:
bool bData = false;//ÊÇ·ñÓÐÊý¾Ý
std::map<TyMatch, _AcMachineNode> mapCh;//×ÓÊ÷
size_t layer = 0;//µ±Ç°²ã
_AcMachineNode *pBack = nullptr;//»ØËݽڵãÖ¸Õë
_AcMachineNode *pFind = nullptr;//²éÕÒÓÐЧ½ÚµãÖ¸Õë
public:
_AcMachineNode()
= default;
_AcMachineNode(const _AcMachineNode &other)
{
operator =(other);
}
//¿½±´º¯Êý£¬¿½±´ºóÐèÒªÖØÐ¹¹ÔìÖ¸Õë
_AcMachineNode &operator =(const _AcMachineNode &other)
{
if(this!=&other) {
bData = other.bData;
mapCh = other.mapCh;
layer = other.layer;
pBack = nullptr;
pFind = nullptr;
}
}
//¹¹ÔìÊý¾Ý
void Construct()
{
bData = true;
}
//Çå³ýÊý¾Ý
void Clear()
{
bData = false;
mapCh.clear();
}
//»ñÈ¡Êý¾Ý±êÇ©
static ConstRetDataType GetData(const _AcMachineNode *pt)
{
if(pt==nullptr)
return false;
else
return pt->bData;
}
};
//AC×Ô¶¯»úÄÚ²¿½ÚµãÀàÐÍ£¬¹þÏ£±íʵÏÖ
template<typename TyMatch, typename TyData>
struct _UnordAcMachineNode
{
using RetDataType = TyData *;
using ConstRetDataType = const TyData *;
constexpr static bool bIsVoid = false;
public:
TyData *pData = nullptr;
std::unordered_map<TyMatch, _UnordAcMachineNode> mapCh;//×ÓÊ÷
size_t layer = 0;//µ±Ç°²ã
_UnordAcMachineNode *pBack = nullptr;//»ØËݽڵãÖ¸Õë
_UnordAcMachineNode *pFind = nullptr;//²éÕÒÓÐЧ½ÚµãÖ¸Õë
public:
_UnordAcMachineNode()
= default;
~_UnordAcMachineNode()
{
delete pData;
}
//¿½±´º¯Êý£¬¿½±´ºóÐèÒªÖØÐ¹¹ÔìÖ¸Õë
_UnordAcMachineNode(const _UnordAcMachineNode &other)
{
operator =(other);
}
_UnordAcMachineNode &operator =(const _UnordAcMachineNode &other)
{
if(this!=&other) {
mapCh = other.mapCh;
//Èô¶Ô·½ÓÐÊý¾Ý
if(other.pData) {
if(pData)
*pData = *other.pData;
else
Construct(other.data);
}
//Èô¶Ô·½Ã»Êý¾Ý
else {
if(pData) {
delete pData;
pData = nullptr;
}
}
//¿½±´ÆäËûÊý¾Ý
mapCh = other.mapCh;
layer = other.layer;
pBack = nullptr;
pFind = nullptr;
}
return *this;
}
//¹¹ÔìÊý¾Ý
template<typename ...Ty_S>
void Construct(Ty_S &&...arg_s)
{
assert(pData==nullptr);
pData = new TyData(std::forward<Ty_S>(arg_s)...);
}
//Çå³ýÊý¾Ý
void Clear()
{
delete pData;
pData = nullptr;
mapCh.clear();
}
//»ñÈ¡Êý¾ÝÖ¸Õë
static RetDataType GetData(_UnordAcMachineNode *pt)
{
if(pt==nullptr)
return nullptr;
else
return pt->pData;
}
static ConstRetDataType GetData(const _UnordAcMachineNode *pt)
{
return GetData((_UnordAcMachineNode *)pt);
}
};
template<typename TyMatch>
struct _UnordAcMachineNode<TyMatch, void>
{
using RetDataType = bool;
using ConstRetDataType = bool;
constexpr static bool bIsVoid = true;
public:
bool bData = false;//ÊÇ·ñÓÐÊý¾Ý
std::unordered_map<TyMatch, _UnordAcMachineNode> mapCh;//×ÓÊ÷
size_t layer = 0;//µ±Ç°²ã
_UnordAcMachineNode *pBack = nullptr;//»ØËݽڵãÖ¸Õë
_UnordAcMachineNode *pFind = nullptr;//²éÕÒÓÐЧ½ÚµãÖ¸Õë
public:
_UnordAcMachineNode()
= default;
_UnordAcMachineNode(const _UnordAcMachineNode &other)
{
operator =(other);
}
//¿½±´º¯Êý£¬¿½±´ºóÐèÒªÖØÐ¹¹ÔìÖ¸Õë
_UnordAcMachineNode &operator =(const _UnordAcMachineNode &other)
{
if(this!=&other) {
bData = other.bData;
mapCh = other.mapCh;
layer = other.layer;
pBack = nullptr;
pFind = nullptr;
}
}
//¹¹ÔìÊý¾Ý
void Construct()
{
bData = true;
}
//Çå³ýÊý¾Ý
void Clear()
{
bData = false;
mapCh.clear();
}
//»ñÈ¡Êý¾Ý±êÇ©
static ConstRetDataType GetData(const _UnordAcMachineNode *pt)
{
if(pt==nullptr)
return false;
else
return pt->bData;
}
};
//binfile½Ó¿Ú
template<typename TyMatch, typename TyData>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _AcMachineNode<TyMatch, TyData> &node)
{
_BinWriteTrieOrAcNodeAssist(bwf, node);
return bwf;
}
template<typename TyMatch, typename TyData>
inline BinReadFile &operator >>(BinReadFile &brf, _AcMachineNode<TyMatch, TyData> &node)
{
_BinReadTrieOrAcNodeAssist(brf, node);
return brf;
}
template<typename TyMatch, typename TyData>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _UnordAcMachineNode<TyMatch, TyData> &node)
{
_BinWriteTrieOrAcNodeAssist(bwf, node);
return bwf;
}
template<typename TyMatch, typename TyData>
inline BinReadFile &operator >>(BinReadFile &brf, _UnordAcMachineNode<TyMatch, TyData> &node)
{
_BinReadTrieOrAcNodeAssist(brf, node);
return brf;
}
template<typename TyNode>
class _AcMachineTemplate;
//AC×Ô¶¯»úËÑË÷ÀàÉÏÏÂÎÄ
template<typename TyNode, typename TyIt>
struct _AcContextTemplate
{
bool bFirst = true;//¼Ç¼Ê×´ÎÆ¥Åä
TyNode *pt = nullptr;//Ê÷½ÚµãÖ¸Õë
TyNode *pFind = nullptr;//ÕýÔÚ²éÕÒÖ¸Õë
TyIt it;//Æ¥Åä´®Ö¸Õë
};
template<typename TyNode, typename TyIt>
inline _AcContextTemplate<TyNode, TyIt> MakeAcContext(const _AcMachineTemplate<TyNode> &, TyIt)
{
return _AcContextTemplate<TyNode, TyIt>();
}
//AC×Ô¶¯»úËÑË÷À֧࣬³ÖvoidÊý¾Ý
template<typename TyNode>
class _AcMachineTemplate
{
template<typename TyNode2>
friend BinWriteFile &operator <<(BinWriteFile &bwf, const _AcMachineTemplate<TyNode2> &acm);
template<typename TyNode2>
friend BinReadFile &operator >>(BinReadFile &brf, _AcMachineTemplate<TyNode2> &acm);
public:
//¸¨ÖúÀàÐÍ
using NodeType = TyNode;
using RetDataType = typename NodeType::RetDataType;
using ConstRetDataType = typename NodeType::ConstRetDataType;
private:
NodeType *pRoot;//¸ù½Úµã
bool bPrepare = true;
public:
//Î忽±´
_AcMachineTemplate():
pRoot(new NodeType())
{
}
~_AcMachineTemplate()
{
delete pRoot;
}
_AcMachineTemplate(const _AcMachineTemplate &other):
_AcMachineTemplate()
{
operator =(other);
}
_AcMachineTemplate(_AcMachineTemplate &&other):
_AcMachineTemplate()
{
operator =(std::move(other));
}
_AcMachineTemplate &operator =(const _AcMachineTemplate &other)
{
if(this!=&other) {
*pRoot = *other.pRoot;
bPrepare = false;
if(other.bPrepare) {
bPrepare = false;
Prepare();
}
}
return *this;
}
_AcMachineTemplate &operator =(_AcMachineTemplate &&other)
{
if(this!=&other) {
std::swap(pRoot, other.pRoot);
std::swap(bPrepare, other.bPrepare);
}
return *this;
}
public:
//×ö×¼±¸£¬ÔÚ½øÐÐÆ¥Åä֮ǰµ÷Óã¬Ò²¿ÉÊÖ¶¯µ÷ÓÃ
void Prepare()
{
if(bPrepare)
return;
std::deque<NodeType *> deqNode;//½ÚµãÕ¹¿ª¶ÓÁÐ
//¹¹ÔìµÚÒ»²ã»ØËÝ
deqNode.push_back(pRoot);
//Õ¹¿ª¶ÓÁÐ
while(!deqNode.empty()) {
//ÿһ¸ö×Ó½Úµã
for(auto &pr: deqNode.front()->mapCh) {
//Ìí¼Ó¶ÓÁÐ
deqNode.push_back(&pr.second);
//ѰÕÒ¸¸½Úµã
auto pFindBack = deqNode.front();
while(pFindBack->pBack!=nullptr) {
pFindBack = pFindBack->pBack;
auto res = pFindBack->mapCh.find(pr.first);
if(res!=pFindBack->mapCh.end()) {
pFindBack = &res->second;
break;
}
}
//¹¹Ô츸ָÕë
pr.second.pBack = pFindBack;
if(NodeType::GetData(pFindBack))
pr.second.pFind = pFindBack;
else
pr.second.pFind = pFindBack->pFind;
pr.second.layer = deqNode.front()->layer+1;
}
//µ¯³ö¶ÓÁÐ
deqNode.pop_front();
}
bPrepare = true;
}
//Ìí¼ÓÆ¥Å乿Ôò
template<typename TyIt, typename ...Ty_S>
bool EmplaceRule(TyIt itSt, TyIt itEd, Ty_S &&...arg_s)
{
bPrepare = false;
NodeType *pNode = pRoot;
while(itSt!=itEd) {
auto res = pNode->mapCh.emplace(std::piecewise_construct,
std::tie(*itSt), std::make_tuple());
pNode = &res.first->second;
bPrepare = bPrepare && !res.second;
++ itSt;
}
if(NodeType::GetData(pNode))
return false;
pNode->Construct(std::forward<Ty_S>(arg_s)...);
return true;
}
//Çå³ý½Úµã
void Clear()
{
pRoot->Clear();
bPrepare = true;
}
//µü´úËÑË÷º¯Êý£¬Êý¾ÝÀàÐÍ·µ»ØÖ¸Õ룬¿ÕÀàÐÍ·µ»Ø²¼¶û
//ÕÒ²»µ½·µ»Ø¿ÕÖ¸Õ룬ÈôÕÒµ½·µ»ØÕÒµ½Î²ºóºÍ³¤¶È£¬Î´ÕÒµ½·µ»Ø´®Î²ºóºÍ0
template<typename TyIt, typename TyCtx= _AcContextTemplate<TyNode, TyIt>>
typename std::enable_if<IsRemoveCVRefSame<_AcContextTemplate<TyNode, TyIt>, TyCtx>::value,
std::tuple<TyIt, size_t, RetDataType>
>::type Search(TyIt itSt, TyIt itEd, TyCtx &&ctx= TyCtx())
{
//×¼±¸
Prepare();
//³õʼ»¯
bool bFirst = false;
if(ctx.bFirst) {
ctx.bFirst = false;
ctx.pt = pRoot;
ctx.it = itSt;
bFirst = true;
}
auto ret = std::make_tuple(ctx.it, (size_t)0, NodeType::GetData((NodeType *)nullptr));
//ÅжÏÊä³öͬһ½Úµã½á¹û
if(ctx.pFind!=nullptr) {
std::get<1>(ret) = ctx.pFind->layer;
std::get<2>(ret) = NodeType::GetData(ctx.pFind);
ctx.pFind = ctx.pFind->pFind;
}
//ÈôΪµÚÒ»´Î²éÕÒÇÒ´æÔÚ¿ÕÆ¥Åä
else if(bFirst && NodeType::GetData(ctx.pt)) {
std::get<1>(ret) = ctx.pt->layer;
std::get<2>(ret) = NodeType::GetData(ctx.pt);
ctx.pFind = ctx.pt->pFind;
}
//·ñÔò²éÕÒÏÂÒ»½Úµã
else {
//¶ÁÈë×Ö·ûÑ­»·
while(ctx.it!=itEd) {
//²éÕÒ»ØËÝ
while(true) {
auto res = ctx.pt->mapCh.find(*ctx.it);
if(res!=ctx.pt->mapCh.end()) {
ctx.pt = &res->second;
break;
}
if(ctx.pt->pBack==nullptr)
break;
ctx.pt = ctx.pt->pBack;
}
++ ctx.it;
//ÈôÕÒµ½´øÊý¾ÝµÄ½Úµã
if(NodeType::GetData(ctx.pt)) {
std::get<1>(ret) = ctx.pt->layer;
std::get<2>(ret) = NodeType::GetData(ctx.pt);
ctx.pFind = ctx.pt->pFind;
break;
}
//ÈôÕÒµ½´ø²éÕÒÊý¾ÝµÄ½Úµã
else if(ctx.pt->pFind!=nullptr) {
ctx.pFind = ctx.pt->pFind;
std::get<1>(ret) = ctx.pFind->layer;
std::get<2>(ret) = NodeType::GetData(ctx.pFind);
ctx.pFind = ctx.pFind->pFind;
break;
}
}
std::get<0>(ret) = ctx.it;
}
return ret;
}
//ÕÒµ½µÚÒ»¸ö£¬Æ¥Åäβºó¿¼Ç°ÓÅÏÈ£¬Æ¥ÅäÊײ¿¿¿Ç°ÓÅÏÈ
template<typename TyIt>
RetDataType Judge(TyIt itSt, TyIt itEd)
{
return std::get<2>(Search(itSt, itEd));
}
//¼ÆÊýÕÒµ½´ÎÊý
template<typename TyIt>
RetDataType Count(TyIt itSt, TyIt itEd)
{
_AcContextTemplate<TyNode, TyIt> ctx;
size_t cnt = 0;
for(; ; ++cnt) {
if(std::get<2>(Search(itSt, itEd, ctx)))
break;
}
return cnt;
}
};
//binfile½Ó¿Ú
template<typename TyNode>
inline BinWriteFile &operator <<(BinWriteFile &bwf, const _AcMachineTemplate<TyNode> &acm)
{
return bwf <<(uint8_t)acm.bPrepare
<<*acm.pRoot;
}
template<typename TyNode>
inline BinReadFile &operator >>(BinReadFile &brf, _AcMachineTemplate<TyNode> &acm)
{
uint8_t bPrepare;
brf >>bPrepare;
acm.bPrepare = false;
brf >>*acm.pRoot;
if(bPrepare)
acm.Prepare();
return brf;
}
//¶¨ÒåËÑË÷Ê÷µÄƽºâÊ÷ʵÏÖ
template<typename TyMatch, typename TyData= void>
using AcMachine = _AcMachineTemplate<_AcMachineNode<TyMatch, TyData>>;
template<typename TyMatch, typename TyData, typename TyIt>
using AcContext = _AcContextTemplate<_AcMachineNode<TyMatch, TyData>, TyIt>;
//¶¨ÒåËÑË÷Ê÷µÄ¹þÏ£±íʵÏÖ
template<typename TyMatch, typename TyData= void>
using UnordAcMachine = _AcMachineTemplate<_UnordAcMachineNode<TyMatch, TyData>>;
template<typename TyMatch, typename TyData, typename TyIt>
using UnordAcContext = _AcContextTemplate<_UnordAcMachineNode<TyMatch, TyData>, TyIt>;
//Ö»ÄÜÌí¼ÓÔªËØµÄͼ£¬Ö§³ÖvoidÊý¾ÝÀàÐÍ
//ÄÚ²¿Îª¶þάÊý×éʵÏÖ
//½Úµãµü´úÆ÷ÔÊÐíʹÓÃÕûÐÎË÷Òý¹¹Ôì
//ClearºÍAssign»áµ¼Öµü´úÆ÷ʧЧ
//ÈÝÆ÷¸´ÖÆ¡¢Òƶ¯¡¢½»»»ºóµü´úÆ÷¾ùÖ¸Ïò¾ÉÈÝÆ÷£¬ÔÊÐíµü´úÆ÷¸üÐÂÈÝÆ÷Ö¸Õë
//TODO: Ïë½á¹¹Éè¼Æ£¬³¢ÊÔ½«½ÚµãÓë±ß¶ÔÓ¦µ½ÕûÐÎË÷ÒýÉÏ
template<typename TyNodeData, typename TyEdgeData>
class AddonlyGraph
{
private:
//±ß½á¹¹Ìå
struct EdgeStruct:
public ValueHolder<TyEdgeData>
{
size_t index;//±ß±àºÅ
//½ÓÊÕÊý¾ÝÀàÐÍÄ£°å²ÎÊýµÄ¹¹Ôì
template<typename ...Tys>
EdgeStruct(size_t o_index, Tys &&...args):
ValueHolder<TyEdgeData>(std::forward<Tys>(args)...), index(o_index)
{
}
};
//½Úµã½á¹¹Ìå
struct NodeStruct:
public ValueHolder<TyNodeData>
{
std::vector<EdgeStruct> vecEdge;//³ö±ßÊý×é
//½ÓÊÕ×óÖµ»òÓÒÖµµÄÊý¾Ý¹¹Ôì
template<typename ...Tys>
NodeStruct(Tys &&...args):
ValueHolder<TyNodeData>(std::forward<Tys>(args)...)
{
}
};
private://¸¨ÖúÀàÐͶ¨Òå
using GraphType = AddonlyGraph<TyNodeData, TyEdgeData>;//ͼÀàÐÍ
public:
using NodeDataType = TyNodeData;//½ÚµãÊý¾ÝÀàÐÍ
using EdgeDataType = TyEdgeData;//±ßÊý¾ÝÀàÐÍ
private://µü´úÆ÷Ä£°å¶¨Òå
//½Úµãµü´úÆ÷Ä£°å¸¨ÖúÀà
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyNodeDataPure>
class TemplateNodeIterAssist;
//½Úµãµü´úÆ÷Ä£°å
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyEdgeDataMy>
class TemplateNodeIter;
//±ßµü´úÆ÷Ä£°å¸¨ÖúÀà
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyNodeDataPure>
class TemplateEdgeIterAssist;
//±ßµü´úÆ÷Ä£°å
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyEdgeDataMy>
class TemplateEdgeIter;
private://µü´úÆ÷Ä£°åÖ¸¶¨ÀàÐͶ¨Òå
//½Úµãµü´úÆ÷¸¨ÖúÀàÖ¸¶¨
using NodeIterAssist = TemplateNodeIter<GraphType, TyNodeData, TyNodeData>;
//½Úµã³£µü´úÆ÷¸¨ÖúÀàÖ¸¶¨
using NodeConstIterAssist = TemplateNodeIter<
const GraphType, const TyNodeData, TyNodeData>;
//±ßµü´úÆ÷¸¨ÖúÀàÖ¸¶¨
using EdgeIterAssist = TemplateEdgeIter<GraphType, TyEdgeData, TyEdgeData>;
//±ß³£µü´úÆ÷¸¨ÖúÀàÖ¸¶¨
using EdgeConstIterAssist = TemplateEdgeIter<
const GraphType, const TyEdgeData, TyEdgeData>;
public:
//½Úµãµü´úÆ÷ÀàÖ¸¶¨
using NodeIter = TemplateNodeIter<GraphType, TyNodeData, TyEdgeData>;
//½Úµã³£µü´úÆ÷ÀàÖ¸¶¨
using NodeConstIter = TemplateNodeIter<
const GraphType, const TyNodeData, const TyEdgeData>;
//±ßµü´úÆ÷ÀàÖ¸¶¨
using EdgeIter = TemplateEdgeIter<GraphType, TyNodeData, TyEdgeData>;
//±ß³£µü´úÆ÷ÀàÖ¸¶¨
using EdgeConstIter = TemplateEdgeIter<
const GraphType, const TyNodeData, const TyEdgeData>;
public://ÓÑÔªÉùÃ÷
friend NodeIter;
friend NodeIterAssist;
friend NodeConstIter;
friend NodeConstIterAssist;
friend EdgeIter;
friend EdgeIterAssist;
friend EdgeConstIter;
friend EdgeConstIterAssist;
private://³ÉÔ±Êý¾Ý
std::vector<NodeStruct> vecNode;//½ÚµãÊý×é
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
AddonlyGraph()
= default;
//¶à¸öÊý¾Ý¹¹Ôì
template<typename ...Ty_S>
explicit AddonlyGraph(size_t size, const Ty_S &...arg_s)
{
Assign(size, arg_s...);
}
public://³ÉÔ±º¯Êý
//¸³Öµº¯Êý
template<typename ...Ty_S>
AddonlyGraph &Assign(size_t size, const Ty_S &...arg_s)
{
vecNode.assign(size, NodeStruct(arg_s...));
return *this;
}
//Ìí¼Ó½Úµã
template<typename TyNodeDataMy>
typename std::enable_if<std::is_convertible<TyNodeDataMy &&, TyNodeData>::value, NodeIter
>::type AddNode(TyNodeDataMy &&data)
{
return EmplaceNode(std::forward<TyNodeDataMy>(data));
}
template<typename ...Tys>
NodeIter EmplaceNode(Tys &&...args)
{
vecNode.emplace_back(std::forward<Tys>(args)...);
return NodeIter(this, vecNode.size()-1);
}
//Ìí¼Ó±ß
template<typename TyEdgeDataMy>
typename std::enable_if<std::is_convertible<TyEdgeDataMy &&, TyEdgeData>::value, EdgeIter
>::type AddEdge(NodeIter fromNode, NodeIter toNode, TyEdgeDataMy &&data)
{
return EmplaceEdge(fromNode, toNode, std::forward<TyEdgeDataMy>(data));
}
//¹¹Ôì±ß
template<typename ...Tys>
EdgeIter EmplaceEdge(NodeIter fromNode, NodeIter toNode, Tys &&...args)
{
vecNode[fromNode.idxNode].vecEdge.emplace_back(
toNode.idxNode, std::forward<Tys>(args)...);
return EdgeIter(this, fromNode.idxNode, vecNode[fromNode.idxNode].vecEdge.size()-1);
}
//Ìí¼ÓË«Ïò±ß
template<typename TyEdgeDataMy>
typename std::enable_if<std::is_convertible<TyEdgeDataMy &&, TyEdgeData>::value,
std::pair<EdgeIter, EdgeIter>
>::type AddDoublyEdge(NodeIter fromNode, NodeIter toNode,
TyEdgeDataMy &&dataGo, TyEdgeDataMy &&dataRev)
{
auto it = AddAdge(fromNode, toNode, std::forward<TyEdgeDataMy>(dataGo));
return std::make_pair(it,
AddAdge(toNode, fromNode, std::forward<TyEdgeDataMy>(dataRev)));
}
private:
//¹¹ÔìË«Ïò±ß¸¨Öúº¯Êý
template<typename TyTupGo, typename TyTupRev, size_t ...c_idxGo_s, size_t ...c_idxRev_s>
std::pair<EdgeIter, EdgeIter> EmplaceDoublyEdgeAssist(NodeIter fromNode,
NodeIter toNode, TyTupGo &&tupGo, TyTupRev &&tupRev,
IndexSequence<c_idxGo_s...>, IndexSequence<c_idxRev_s...>)
{
static auto funcGo = std::mem_fn(&AddonlyGraph::EmplaceEdge<
typename TypeAttachAttribute<TyTupGo &&, typename std::tuple_element<
c_idxGo_s, typename RemoveCVRef<TyTupGo>::type>::type>::type...>);
static auto funcRev = std::mem_fn(&AddonlyGraph::EmplaceEdge<
typename TypeAttachAttribute<TyTupRev &&, typename std::tuple_element<
c_idxRev_s, typename RemoveCVRef<TyTupRev>::type>::type>::type...>);
auto itGo = TupleInvoke(funcGo,
std::tuple_cat(std::forward_as_tuple(this, fromNode, toNode), std::forward<TyTupGo>(tupGo)));
auto itRev = TupleInvoke(funcRev,
std::tuple_cat(std::forward_as_tuple(this, toNode, fromNode), std::forward<TyTupRev>(tupRev)));
return std::make_pair(itGo, itRev);
}
public:
//¹¹ÔìË«Ïò±ß£¬ÔÚtupleÀïÃæ·Å¹¹Ôì²ÎÊý
template<typename TyTupGo, typename TyTupRev>
std::pair<EdgeIter, EdgeIter> EmplaceDoublyEdge(NodeIter fromNode,
NodeIter toNode, TyTupGo &&tupGo, TyTupRev &&tupRev)
{
return EmplaceDoublyEdgeAssist(fromNode, toNode,
std::forward<TyTupGo>(tupGo), std::forward<TyTupRev>(tupRev),
MakeIndexSequence<std::tuple_size<
typename std::remove_reference<TyTupGo>::type>::value>(),
MakeIndexSequence<std::tuple_size<
typename std::remove_reference<TyTupRev>::type>::value>());
}
//Çå³ýͼ
void Clear()
{
vecNode.clear();
}
//µü´ú½Úµã
NodeIter NodeBegin()
{
return NodeIter(this, 0);
}
NodeConstIter NodeBegin() const
{
return NodeConstIter(this, 0);
}
NodeIter begin()
{
return NodeBegin();
}
NodeConstIter begin() const
{
return NodeBegin();
}
NodeConstIter NodeConstBegin()
{
return NodeBegin();
}
NodeIter NodeEnd()
{
return NodeIter(this, vecNode.size());
}
NodeConstIter NodeEnd() const
{
return NodeConstIter(this, vecNode.size());
}
NodeIter end()
{
return NodeEnd();
}
NodeConstIter end() const
{
return NodeEnd();
}
NodeConstIter NodeConstEnd()
{
return NodeEnd();
}
//½ÚµãÊý
size_t NodeSize() const
{
return vecNode.size();
}
};
//µãµü´úÆ÷Ä£°å¸¨ÖúÀà
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyNodeDataPure>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateNodeIterAssist:
public std::iterator<std::bidirectional_iterator_tag, TyNodeDataMy,
ptrdiff_t, TyNodeDataMy *, TyNodeDataMy &>
{
protected://³ÉÔ±Êý¾Ý
GraphTypeMy *pGraph;//ͼָÕë
size_t idxNode;//½Úµã
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
TemplateNodeIterAssist():
pGraph(nullptr), idxNode(0)
{
}
//¹¹Ô캯Êý£¬ÔÊÐíÍⲿ½øÐй¹Ôì
explicit TemplateNodeIterAssist(GraphTypeMy *o_graph, size_t o_idxNode):
pGraph(o_graph), idxNode(o_idxNode)
{
}
public://ÔËËã·ûÖØÔØ
//½âÒýÓòÙ×÷
TyNodeDataMy &operator *() const
{
return pGraph->vecNode[idxNode].hold;
}
TyNodeDataMy *operator ->() const
{
return &operator *();
}
};
//µãµü´úÆ÷Ä£°å¸¨ÖúÀàÌØ»¯
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyNodeDataMy>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateNodeIterAssist<
GraphTypeMy, TyNodeDataMy, void
>: public std::iterator<std::bidirectional_iterator_tag, TyNodeDataMy,
ptrdiff_t, void, void>
{
protected://³ÉÔ±Êý¾Ý
GraphTypeMy *pGraph;//ͼָÕë
size_t idxNode;//½Úµã
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
TemplateNodeIterAssist():
pGraph(nullptr), idxNode(0)
{
}
//¹¹Ô캯Êý£¬ÔÊÐíÍⲿ½øÐй¹Ôì
explicit TemplateNodeIterAssist(GraphTypeMy *o_graph, size_t o_idxNode):
pGraph(o_graph), idxNode(o_idxNode)
{
}
};
//½Úµãµü´úÆ÷Ä£°åÀà
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyEdgeDataMy>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateNodeIter:
public TemplateNodeIterAssist<GraphTypeMy, TyNodeDataMy, TyNodeData>
{
public://ÓÑÔª
friend AddonlyGraph<TyNodeData, TyEdgeData>;
friend NodeIter;
friend NodeConstIter;
friend EdgeIter;
friend EdgeConstIter;
private://¸¨ÖúÀàÐÍ
//¶ÔÓ¦µÄ±ßµü´úÆ÷
using EdgeIterMy = TemplateEdgeIter<GraphTypeMy, TyNodeDataMy, TyEdgeDataMy>;
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
TemplateNodeIter()
= default;
//¼Ì³Ð¸¨ÖúÀàµÄ¹¹Ô캯Êý
using TemplateNodeIterAssist<GraphTypeMy, TyNodeDataMy, TyNodeData>::TemplateNodeIterAssist;
//Óɷdz£À๹Ôì³£Àà
TemplateNodeIter(const NodeIter &other)
{
operator =(other);
}
TemplateNodeIter &operator =(const NodeIter &other)
{
if((void *)this!=(void *)&other) {
this->pGraph = other.pGraph;
this->idxNode = other.idxNode;
}
return *this;
}
public://ÔËËã·ûÖØÔØ
//µÝÔöµÝ¼õ²Ù×÷
TemplateNodeIter &operator ++()
{
++ this->idxNode;
return *this;
}
TemplateNodeIter operator ++(int)
{
TemplateNodeIter ret(*this);
operator ++();
return ret;
}
TemplateNodeIter &operator --()
{
-- this->idxNode;
return *this;
}
TemplateNodeIter operator --(int)
{
TemplateNodeIter ret(*this);
operator --();
return ret;
}
//±È½Ï²Ù×÷
template<typename GraphTypeOther, typename TyNodeDataOther, typename TyEdgeDataOther>
bool operator ==(const TemplateNodeIter<
GraphTypeOther, TyNodeDataOther, TyEdgeDataOther> &other) const
{
return this->idxNode==other.idxNode;
}
template<typename GraphTypeOther, typename TyNodeDataOther, typename TyEdgeDataOther>
bool operator !=(const TemplateNodeIter<
GraphTypeOther, TyNodeDataOther, TyEdgeDataOther> &other) const
{
return !operator ==(other);
}
public://³ÉÔ±º¯Êý
//³ö±ßµü´ú²Ù×÷
EdgeIterMy EdgeBegin() const
{
return EdgeIterMy(this->pGraph, this->idxNode, 0);
}
EdgeIterMy begin() const
{
return EdgeBegin();
}
EdgeConstIter EdgeConstBegin() const
{
return EdgeBegin();
}
EdgeIterMy EdgeEnd() const
{
return EdgeIterMy(this->pGraph, this->idxNode, this->pGraph->vecNode[this->idxNode].vecEdge.size());
}
EdgeIterMy end() const
{
return EdgeEnd();
}
EdgeConstIter EdgeConstEnd() const
{
return EdgeEnd();
}
//´¦±ßÊý
size_t EdgeSize() const
{
return this->pGraph->vecNode[this->idxNode].size();
}
//¸Ä±äÖ¸Ïò²Ù×÷
void ChangePointer(GraphTypeMy *o_graph)
{
this->pGraph = o_graph;
}
};
//±ß´úÆ÷Ä£°å¸¨ÖúÀà
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyEdgeDataMy, typename TyEdgeDataPure>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateEdgeIterAssist:
public std::iterator<std::bidirectional_iterator_tag, TyEdgeDataMy,
ptrdiff_t, TyEdgeDataMy *, TyEdgeDataMy &>
{
protected://³ÉÔ±Êý¾Ý
GraphTypeMy *pGraph;//ͼָÕë
size_t idxNode;//½ÚµãÐòºÅ
size_t idxEdge;//±ßÐòºÅ
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
TemplateEdgeIterAssist():
pGraph(nullptr), idxNode(0), idxEdge(0)
{
}
protected:
//¹¹Ô캯Êý£¬²»ÔÊÐíÍⲿ½øÐй¹Ôì
explicit TemplateEdgeIterAssist(GraphTypeMy *o_graph, size_t o_idxNode, size_t o_idxEdge):
pGraph(o_graph), idxNode(o_idxNode), idxEdge(o_idxEdge)
{
}
public://ÔËËã·ûÖØÔØ
//½âÒýÓòÙ×÷
TyEdgeDataMy &operator *() const
{
return pGraph->vecNode[idxNode].vecEdge[idxEdge].hold;
}
TyEdgeDataMy *operator ->() const
{
return &operator *();
}
};
//±ßµü´úÆ÷Ä£°å¸¨ÖúÀàÌØ»¯
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyEdgeDataMy>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateEdgeIterAssist<
GraphTypeMy, TyEdgeDataMy, void
>: public std::iterator<std::bidirectional_iterator_tag, TyEdgeDataMy,
ptrdiff_t, void, void>
{
protected://³ÉÔ±Êý¾Ý
GraphTypeMy *pGraph;//ͼָÕë
size_t idxNode;//½ÚµãÐòºÅ
size_t idxEdge;//±ßÐòºÅ
public://»ù±¾º¯Êý
//ĬÈϹ¹Ôì
TemplateEdgeIterAssist():
pGraph(nullptr), idxNode(0), idxEdge(0)
{
}
protected:
//¹¹Ô캯Êý£¬²»ÔÊÐíÍⲿ½øÐй¹Ôì
explicit TemplateEdgeIterAssist(GraphTypeMy *o_graph, size_t o_idxNode, size_t o_idxEdge):
pGraph(o_graph), idxNode(o_idxNode), idxEdge(o_idxEdge)
{
}
};
//±ßµü´úÆ÷Ä£°åÀà
template<typename TyNodeData, typename TyEdgeData>
template<typename GraphTypeMy, typename TyNodeDataMy, typename TyEdgeDataMy>
class AddonlyGraph<TyNodeData, TyEdgeData>::TemplateEdgeIter:
public TemplateEdgeIterAssist<GraphTypeMy, TyEdgeDataMy, TyEdgeData>
{
public://ÓÑÔª
friend AddonlyGraph<TyNodeData, TyEdgeData>;
friend NodeIter;
friend NodeConstIter;
friend EdgeIter;
friend EdgeConstIter;
private://¸¨ÖúÀàÐÍ
//¶ÔÓ¦µÄ½Úµãµü´úÆ÷
using NodeIterMy = TemplateNodeIter<GraphTypeMy, TyNodeDataMy, TyEdgeDataMy>;
public://»ù±¾º¯Êý
//¼Ì³Ð¸¨ÖúÀàµÄ¹¹Ô캯Êý
using TemplateEdgeIterAssist<GraphTypeMy, TyEdgeDataMy, TyEdgeData>::TemplateEdgeIterAssist;
//Óɷdz£À๹Ôì³£Àà
TemplateEdgeIter(const EdgeIter &other)
{
operator =(other);
}
TemplateEdgeIter &operator =(const EdgeIter &other)
{
if((void *)this!=(void *)&other) {
this->pGraph = other.pGraph;
this->idxNode = other.idxNode;
this->idxEdge = other.idxEdge;
}
return *this;
}
public://ÔËËã·ûÖØÔØ
//µÝÔöµÝ¼õÔì×÷
TemplateEdgeIter &operator ++()
{
++ this->idxEdge;
return *this;
}
TemplateEdgeIter operator ++(int)
{
TemplateEdgeIter ret(*this);
operator ++();
return ret;
}
TemplateEdgeIter &operator --()
{
-- this->idxEdge;
return *this;
}
TemplateEdgeIter operator --(int)
{
TemplateEdgeIter ret(*this);
operator --();
return ret;
}
//±È½Ï²Ù×÷
template<typename GraphTypeOther, typename TyNodeDataOther, typename TyEdgeDataOther>
bool operator ==(const TemplateEdgeIter<
GraphTypeOther, TyNodeDataOther, TyEdgeDataOther> &other) const
{
return this->idxNode==other.idxNode && this->idxEdge==other.idxEdge;
}
template<typename GraphTypeOther, typename TyNodeDataOther, typename TyEdgeDataOther>
bool operator !=(const TemplateEdgeIter<
GraphTypeOther, TyNodeDataOther, TyEdgeDataOther> &other) const
{
return !operator ==(other);
}
public://³ÉÔ±º¯Êý
//»ñÈ¡Á¬½Ó½Úµã
NodeIterMy NodeFrom() const
{
return NodeIterMy(this->pGraph, this->idxNode);
}
NodeConstIter NodeConstFrom() const
{
return NodeFrom();
}
NodeIterMy NodeTo() const
{
return NodeIterMy(this->pGraph, this->pGraph->vecNode[this->idxNode].vecEdge[this->idxEdge].index);
}
NodeIterMy NodeConstTo() const
{
return NodeTo();
}
};
/*ͼ·ÖÀàÉèÏë
1£¬Ö»ÄÜÌí¼ÓµÄͼ£º
AddNode
AddEdge
Clear
NodeBegin
NodeEnd
NodeIter::EdgeBegin
NodeIter::EdgeEnd
NodeIter::operator ++
NodeIter::operator --
NodeIter::operator *
EdgeIter::NodeFrom
EdgeIter::NodeTo
EdgeIter::operator ++
NodeIter::operator --
EdgeIter::operator *
2£¬Ö»ÄÜÌí¼ÓµÄͼ£¬¿ÉÒԲ鿴À´Ô´±ß£º
È«²¿1º¯Êý
NodeIter::EdgeFromBegin
NodeIter::EdgeFromEnd
3£¬Ö»ÄÜÌí¼ÓµÄͼ£¬¿ÉÒÔ¸ù¾ÝÁ½¸ö¶¥µãÕÒÀ´Ô´
È«²¿1º¯Êý
GetEdge
4£¬Ö»ÄÜÌí¼ÓµÄͼ£¬´øÓÐÁ½ÕßÊôÐÔ
È«²¿2£¬3º¯Êý
5£¬¿ÉÒÔÐ޸ĵÄͼ
È«²¿1º¯Êý
È«²¿2º¯Êý
DelNode
DelEdge
6£¬ÔÚ5»ù´¡ÉÏÔö¼Ó
3¹¦ÄÜ£¬»¹Ã»ÏëºÃ
*/
//µ¥´¿Ðνá¹û״̬
enum class SimplexStatus
{
result, infeasible, unbounded,//Óнá¹û£¬Î޽⣬ÎÞ½ç
};
//µ¥´¿Ðθ¨ÖúÐýת
template<typename Ty>
inline void _SimplexAssistPivot(std::vector<std::vector<Ty>> &aMatrix, std::vector<Ty> &bVector,
std::vector<Ty> &cVector, Ty &vValue, std::vector<int> &bSet, std::vector<int> &nSet,
int lIndex, int eIndex)
{
int mNum= (int)bVector.size(), nNum= (int)cVector.size();//Ô¼ÊøÊý£¬±äÁ¿Êý
//ת»»»»³ö±äÁ¿ËùÔÚÐÐÒ»ÐÐ
aMatrix[lIndex][eIndex] = 1/aMatrix[lIndex][eIndex];
bVector[lIndex] *= aMatrix[lIndex][eIndex];
for(int j=0; j<nNum; ++j) {
if(j==eIndex)
continue;
aMatrix[lIndex][j] *= aMatrix[lIndex][eIndex];
}
//ת»»¾ØÕóÆäËûÐÐ
for(int i=0; i<mNum; ++i) {
if(i==lIndex)
continue;
bVector[i] -= aMatrix[i][eIndex]*bVector[lIndex];
for(int j=0; j<nNum; ++j) {
if(j==eIndex)
continue;
aMatrix[i][j] -= aMatrix[i][eIndex]*aMatrix[lIndex][j];
}
aMatrix[i][eIndex] *= -aMatrix[lIndex][eIndex];
}
//ת»»Ä¿±êº¯Êý
vValue += cVector[eIndex]*bVector[lIndex];
for(int j=0; j<nNum; ++j) {
if(j==eIndex)
continue;
cVector[j] -= cVector[eIndex]*aMatrix[lIndex][j];
}
cVector[eIndex] *= -aMatrix[lIndex][eIndex];
//ת»»Ë÷Òý
std::swap(bSet[lIndex], nSet[eIndex]);
}
//µ¥´¿Ðθ¨ÖúË㷨ѭ»·Ö÷Ìå
template<typename Ty>
inline SimplexStatus _SimplexAssistLoop(std::vector<std::vector<Ty>> &aMatrix, std::vector<Ty> &bVector,
std::vector<Ty> &cVector, Ty &vValue, std::vector<int> &bSet, std::vector<int> &nSet, int ulp)
{
int mNum= (int)bVector.size(), nNum= (int)cVector.size();//Ô¼ÊøÊý£¬±äÁ¿Êý
//µ¥´¿ÐÎÑ­»·
while(true) {
//ÕÒ»»Èë»»³ö±äÁ¿Ñ­»·
bool bFirst = true;
int lIndex, eIndex;
while(true) {
//ÕÒ»»Èë±äÁ¿
eIndex = -1;
Ty maxC = -std::numeric_limits<Ty>::infinity();
for(int j=0; j<nNum; ++j) {
if(bFirst) {
if(cVector[j]>maxC) {
eIndex = j;
maxC = cVector[j];
}
}
else {
//ÍË»¯Ê±Ñ¡±êºÅ×îС
if(FloatGT(cVector[j], 0.0, true, ulp) && (eIndex==-1 || nSet[j]<nSet[eIndex])) {
eIndex = j;
maxC = cVector[j];
}
}
}
if(FloatLTE(maxC, 0.0, true, ulp))
return SimplexStatus::result;
//ÕÒ»»³ö±äÁ¿
lIndex = -1;
Ty minB = std::numeric_limits<Ty>::infinity();
for(int i=0; i<mNum; ++i) {
if(FloatGT(aMatrix[i][eIndex], 0.0, true, ulp)) {
Ty tmp = bVector[i]/aMatrix[i][eIndex];
if(tmp<minB) {
minB = tmp;
lIndex = i;
}
}
}
//ÅжÏÎÞ½ç
if(lIndex==-1) {
vValue = std::numeric_limits<Ty>::infinity();
return SimplexStatus::unbounded;
}
//ÍË»¯Ôò¼ÌÐøÑ­»·
if(bFirst && FloatEQ(minB, 0.0, true, ulp))
bFirst = false;
else
break;
}
//Ðýת
_SimplexAssistPivot(aMatrix, bVector, cVector, vValue, bSet, nSet, lIndex, eIndex);
}
}
//µ¥´¿Ðθ¨Öú³õʼ»¯
template<typename Ty>
inline SimplexStatus _SimplexAssistInit(std::vector<std::vector<Ty>> &aMatrix, std::vector<Ty> &bVector,
std::vector<Ty> &cVector, Ty &vValue, std::vector<int> &bSet, std::vector<int> &nSet, int ulp)
{
int mNum= (int)bVector.size(), nNum= (int)cVector.size();//Ô¼ÊøÊý£¬±äÁ¿Êý
//Åжϻù±¾½â¿ÉÐÐÐÔ
bool bPoss = true;
bSet.reserve(mNum);
nSet.reserve(nNum+1);
for(int j=0; j<nNum; ++j)
nSet.push_back(j);
Ty minB = std::numeric_limits<Ty>::infinity();
int lIndex = -1;
for(int i=0; i<mNum; ++i) {
bSet.push_back(nNum+i);
if(bVector[i]<minB) {
minB = bVector[i];
lIndex = i;
}
}
if(FloatGTE(minB, 0.0, true, ulp))
return SimplexStatus::result;
//¹¹Ô츨Öú¹æ»®
Ty vValue2 = 0;
std::vector<Ty> cVector2(nNum+1, 0);
cVector2[nNum] = -1;
for(int i=0; i<mNum; ++i)
aMatrix[i].push_back(-1);
nSet.push_back(-1);
//³õʼÐýת²¢Çó½â
_SimplexAssistPivot(aMatrix, bVector, cVector2, vValue2, bSet, nSet, lIndex, nNum);
SimplexStatus status = _SimplexAssistLoop(aMatrix, bVector, cVector2, vValue2, bSet, nSet, ulp);
assert(status==SimplexStatus::result);
//ÅжϿÉÐÐÐÔ
status = FloatEQ(vValue2, 0.0, true, ulp) ?
SimplexStatus::result : SimplexStatus::infeasible;
//·´Ðýת¸¨Öú±äÁ¿
lIndex = (int)(std::find(bSet.begin(), bSet.end(), -1)-bSet.begin());
int eIndex;
if(lIndex!=mNum) {
eIndex = -1;
for(int j=0; j<nNum+1; ++j) {
if(FloatNEQ(aMatrix[lIndex][j], 0.0, true, ulp)) {
eIndex = j;
break;
}
}
assert(eIndex!=-1);
_SimplexAssistPivot(aMatrix, bVector, cVector2, vValue2, bSet, nSet, lIndex, eIndex);
}
else {
eIndex = (int)(std::find(nSet.begin(), nSet.end(), -1)-nSet.begin());
assert(eIndex!=nNum+1);
}
//½»»»¸¨Öú±äÁ¿
if(eIndex!=nNum) {
for(int i=0; i<mNum; ++i)
std::swap(aMatrix[i][eIndex], aMatrix[i][nNum]);
std::swap(nSet[eIndex], nSet[nNum]);
}
//È¥³ý¸¨Öú±äÁ¿
for(int i=0; i<mNum; ++i)
aMatrix[i].pop_back();
nSet.pop_back();
cVector2.assign(nNum, 0);
for(int j=0; j<nNum; ++j) {
if(nSet[j]<nNum)
cVector2[j] = cVector[nSet[j]];
}
for(int i=0; i<mNum; ++i) {
if(bSet[i]<nNum) {
vValue += cVector[bSet[i]]*bVector[i];
for(int j=0; j<nNum; ++j) {
cVector2[j] -= cVector[bSet[i]]*aMatrix[i][j];
}
}
}
std::swap(cVector, cVector2);
return status;
}
//µ¥´¿Ð稣¬Ä£°åΪ¸¡µãÊý
//²ÎÊýΪ±ê×¼Ðͼ´£ºÏµÊý¾ØÕó¡¢³£ÊýÏòÁ¿¡¢Ä¿±êϵÊýÏòÁ¿¡¢Ä¿±ê³£ÊýÖµ£¬¸¡µã¾ø¶ÔÎó²î½ç±¶ÂÊ
//·µ»ØÖµÎª×´Ì¬¡¢½âÏòÁ¿¡¢»ù±¾±äÁ¿ÐòºÅ¡¢·Ç»ù±¾±äÁ¿ÐòºÅ
//aMatrix¡¢bVector¡¢cVectorÖоùΪΪ×îÖÕËɳÚÐ͵Ľṹ£¬vValueÊÇÄ¿±êÖµ
//±ê×¼Ð͵ÄÑùÀý£º
//MAX: cVector^T * x + vValue
//s.t.£ºaMatrix * x <= bVector
template<typename Ty>
inline typename std::enable_if<std::is_floating_point<Ty>::value,
std::tuple<SimplexStatus, std::vector<Ty>, std::vector<int>, std::vector<int>>
>::type SimplexAlgo(std::vector<std::vector<Ty>> &aMatrix, std::vector<Ty> &bVector,
std::vector<Ty> &cVector, Ty &vValue, int ulp= 2000)
{
int mNum= (int)bVector.size(), nNum= (int)cVector.size();//Ô¼ÊøÊý£¬±äÁ¿Êý
std::vector<int> bSet, nSet;//»ù±¾¡¢·Ç»ù±¾±äÁ¿Ë÷Òýϱê
std::vector<Ty> resVector;//½âϵÊýÏòÁ¿
//ÕÒ³õʼ½â
SimplexStatus status = _SimplexAssistInit(aMatrix, bVector, cVector, vValue, bSet, nSet, ulp);
if(status==SimplexStatus::infeasible)
return make_tuple(status, resVector, bSet, nSet);
//µ¥´¿ÐÎÑ­»·
status = _SimplexAssistLoop(aMatrix, bVector, cVector, vValue, bSet, nSet, ulp);
if(status==SimplexStatus::unbounded)
return make_tuple(status, resVector, bSet, nSet);
//Éú³É½âÏòÁ¿
resVector.resize(nNum, 0);
for(int i=0; i<mNum; ++i) {
if(bSet[i]<nNum)
resVector[bSet[i]] = bVector[i];
}
return make_tuple(status, std::move(resVector), std::move(bSet), std::move(nSet));
}