二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
寻找二分图的连通子图,用于解决传导等价类问题。
图1 中有两个连通子图
C++代码:
//输入为二部图的边集合,无重复 int findEqualSetBinGraph( std::hash_multimap<int,int> &equelHashL, std::hash_multimap<int,int> &equelHashR, std::vector<int> &vetexL, std::vector<int> &vetexR, std::vector< std::pair<std::vector<int>,std::vector<int> > > &equelSet, bool bStack ) { //使用堆栈,删除遍历过的边 if ( equelHashL.size() >0 ) { std::stack<std::pair< int, int > > edgeEs;//使用边堆栈 std::stack< int > pSL,pSR;//左边堆栈 std::vector< int > pVL,pVR;//左右等价集合 for ( int i=0; i< vetexL.size();++i) {//从左侧开始//遍历过的顶点边的个数为0 pVL.resize(0); pVR.resize(0); int VL = vetexL[i]; pSL.push(vetexL[i]); pVL.push_back(VL); while ( !pSL.empty() ) { VL = pSL.top(); auto ptr =equelHashR.find(VL); int C = equelHashR.count(VL); if ( C> 0) { auto ptr1 =equelHashR.lower_bound(VL); auto ptr2 =equelHashR.upper_bound(VL); for (int i=0;i<C;++i) { pSR.push(ptr1->second); pVR.push_back(ptr1->second); ++ptr1; } pSL.pop(); //去除掉相连的边 equelHashR.erase( VL ); //遍历对方的边 while ( !pSR.empty() ) { int VR = pSR.top(); auto ptr =equelHashL.find(VR); int C = equelHashL.count(VR); if ( C > 1 ) { auto ptr1 =equelHashL.lower_bound(VR); auto ptr2 =equelHashL.upper_bound(VR); for (int i=0;i<C;++i)//绕过第一个,必须要顺序排列才能使用 { if ( ptr1->second != VL ) { pSL.push(ptr1->second); pVL.push_back( ptr1->second ); //删除右边元素 auto ptrR =equelHashR.lower_bound( ptr1->second ); for ( int i =0; i< equelHashR.count( ptr1->second ); ++i ) { if ( ptrR->second == VR) { equelHashR.erase(ptrR); break; } else { ++ptrR; } } } ++ptr1; } pSR.pop(); equelHashL.erase( VR ); } else { //删除右边元素 int VR = pSR.top(); auto ptrR = equelHashL.lower_bound( VR ); for ( int i =0; i< equelHashL.count( VR ); ++i ) { if ( ptrR->second == VL) { equelHashL.erase(ptrR); break; } else { ++ptrR; } } pSR.pop(); } } } else { pSL.pop(); } } if ( pVL.size()>0 && pVR.size()>0 ) { equelSet.push_back( std::make_pair( pVL,pVR ) ); } } } return 1; } //输入为二部图的边集合,有重复 int findEqualSetBinGraph( std::vector< std::pair<int,int> > &edgeSet, std::vector< std::pair<std::vector<int>,std::vector<int> > > &equelSet, bool bStack ) { //4.2筛选集合//划分等价类//使用查找划分等价类 std::vector< std::pair<int,int> > equelLabelL,equelLabelR,equelLabelMin,equelLabelMinMirro; equelLabelL.reserve(edgeSet.size() ); //等价集合 std::vector< std::pair<std::vector<int>,std::vector<int> > > equelSetL,equelSetR;//,equelSet,; std::map<int,int> equelMapL,equelMapR;//使用多值哈希//设置重复集合//用于最后合并连通域 std::hash_multimap<int,int> equelHashL,equelHashR; std::vector<int> vetexL,vetexR;//顶点集合 if ( edgeSet.size()>0 ) { std::qsort(&edgeSet[0],edgeSet.size(),sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntFirst); //使用基数排序//一次合并完成 { int idxS =0; int idxE =0; int vL; vL = edgeSet[0].first; for ( idxE ; idxE< edgeSet.size(); ++idxE ) { if ( idxE == 0 ) { continue; } if ( vL == edgeSet[idxE].first ){ } else { vL = edgeSet[idxE].first; std::qsort(&edgeSet[idxS],idxE-idxS,sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntSecond ); idxS = idxE; } } std::qsort(&edgeSet[idxS],idxE-idxS,sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntSecond ); } equelLabelMin.reserve( edgeSet.size() );//equelLabelMin.reserve( equelLabelR.size() ); { int vL,vR; vL = edgeSet.begin()->first; vR = edgeSet.begin()->second; equelLabelMin.push_back( std::make_pair(vL,vR) ); for ( auto ptr = edgeSet.begin(); ptr!= edgeSet.end(); ++ptr) { if (ptr == edgeSet.begin()) {//跳过第一个 continue; } if ( vL == ptr->first && vR == ptr->second) { } else { vL = ptr->first; vR = ptr->second; equelLabelMin.push_back( std::make_pair(vL,vR) ); } //vL = ptr->first; //vR = ptr->second; } } for ( auto ptr = equelLabelMin.begin(); ptr!= equelLabelMin.end(); ++ptr) { equelHashR.insert( *ptr ); equelLabelMinMirro.push_back( std::make_pair( ptr->second,ptr->first ) ); } std::qsort(&equelLabelMinMirro[0],equelLabelMinMirro.size(),sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntFirst ); { int idxS =0; int idxE =0; int vL = equelLabelMinMirro[0].first; for ( idxE ; idxE< equelLabelMinMirro.size(); ++idxE ) { if ( idxE == 0 ) { continue; } if ( vL == equelLabelMinMirro[idxE].first ){ } else { vL = equelLabelMinMirro[idxE].first; std::qsort(&equelLabelMinMirro[idxS],idxE-idxS,sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntSecond ); idxS = idxE; } } std::qsort(&equelLabelMinMirro[idxS],idxE-idxS,sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntSecond ); } for ( auto ptr = equelLabelMinMirro.begin(); ptr!= equelLabelMinMirro.end(); ++ptr) { equelHashL.insert(*ptr );//多值hash和多值map都不能剔除重复条目,不应该啊! } bool bStack = true; //4.3 找出顶点集合//暂时不需要,根据所有的边找出顶点 vetexL.reserve(equelLabelMin.size()); { int vL,vR; vL = equelLabelMin.begin()->first; vetexL.push_back(vL); for (auto ptr = equelLabelMin.begin(); ptr!= equelLabelMin.end();++ptr) { if (ptr == equelLabelMin.begin()) {//跳过第一个 continue; } if ( vL == ptr->first ){ } else { vL = ptr->first; vetexL.push_back(vL); } } } vetexR.reserve( equelLabelMinMirro.size() ); { int vL,vR; vR = equelLabelMinMirro.begin()->first; vetexR.push_back(vR); for (auto ptr = equelLabelMinMirro.begin(); ptr!= equelLabelMinMirro.end();++ptr) { if ( ptr == equelLabelMinMirro.begin()) {//跳过第一个 continue; } if ( vR == ptr->first ){ } else { vR = ptr->first; vetexR.push_back(vR); } } } } //使用堆栈法寻找连通子图 //边集合: equelLabelMin,equelLabelMinMirros,但使用equelHashL equelHashR 顶点集合: vetexL,vetexR findEqualSetBinGraph(equelHashL,equelHashR,vetexL,vetexR,equelSet,bStack ); return 1; }