您的位置:首页 > 编程语言

精确覆盖问题学习笔记(五)——优化算法的实现代码

2013-06-18 07:24 926 查看
//文件node.h
#pragma once

struct CNode
{
	CNode* Left;      //左节点指针
	CNode* Right;     //右节点指针

	CNode* Up;        //上节点指针,对列节点,则为本列最后一个元素的指针
	CNode* Down;      //下节点指针,对列节点,则为本列第一个元素的指针
	
	int name;			//对普通节点,为所在子集的编号,即行号;
						//对列节点,为列编号
};

struct CColumnHead:public CNode
{
	int size;   //本列元素的个数
};

struct CGrid:public CNode
{
	CColumnHead* columnHead;   //列头节点的指针

};
//文件ExactCover.h
#pragma once
#include <vector>
#include <set>
#include <iostream>
#include <fstream>
using namespace std;
#include "node.h"

class CExactCover
{
public:
	CExactCover(const vector<vector <int> >& matrix); //从矩阵中读入数据,建立链表
	~CExactCover(void);

private:
	const CColumnHead* getColumn(int name)const;
	const CColumnHead* selectColumn()const;        //选择含1个数最少的列      
	void cover(const CColumnHead *c);        //将某一列及其相关的节点从矩阵中删除
	void uncover(const CColumnHead *c);      //将某一列及其相关的节点重新加入到矩阵中
	void CreateHead(const vector<vector <int> >& matrix); //建立头节点链表
	void CreateRows(const vector<vector <int> >& matrix);  //建立数据节点

	bool search();   //求解算法
	void print(const vector<vector <int> >& matrix,ostream &os) const; //输出可行解private:set<int>m_solution; //解集
	CColumnHead* m_master; //列头链表的头节点
};
//文件ExactCover.cpp
#include <iomanip>
#include <sstream>
#include <map>
using namespace std;
#include "ExactCover.h"
void CExactCover::CreateHead( const vector<vector <int> >& matrix )
{
	m_master = new CColumnHead;
	m_master->size = 0;
	m_master->Left  = m_master;
	m_master->Right = m_master;

	CColumnHead* prev = m_master;

	const int elementNum = matrix[0].size();
	for (int i = 0
		; i < elementNum
		;++i
		)
	{
		CColumnHead* c=new CColumnHead;
		c->name = i+1;
		c->size = 0;
		
		prev->Right = c;
		c->Left = prev;

		c->Right = m_master;
		m_master->Left = c;

		c->Up = c;
		c->Down = c;

		prev = c;
		++m_master->size;
	}
}

void CExactCover::CreateRows( const vector<vector <int> >& matrix )
{
	const int subsetNum=matrix.size();
	const int elementNum = matrix[0].size();
	
	for (int i=0;i<subsetNum;++i)
	{
		CGrid* head=NULL;
		CGrid* prev=NULL;
		int num=0;
		for(int j=0;j<elementNum;++j)
		{
			if (matrix[i][j]==1)
			{
				++num;

				CGrid* cell=new CGrid;
				cell->name=i;
				
				CColumnHead* c=const_cast<CColumnHead*>(getColumn(j+1));
				CGrid* lastCell = static_cast<CGrid*>(c->Up);
				
				lastCell->Down = cell;
				cell->Up= lastCell;

				c->Up = cell;
				cell->Down = c;
				cell->columnHead = c;

				++c->size;
				
				if (num==1)
				{
					head = cell;
					prev = head;
				}
				
				cell->Left =  prev;
				cell->Right = head;
					
				head->Left = cell;
				prev->Right = cell;
				
				prev = cell;
			}
		}
	}
}

CExactCover::CExactCover(const vector<vector <int> >& matrix)
{
	CreateHead(matrix);
	CreateRows(matrix);

}

CExactCover::~CExactCover(void)
{

}
void CExactCover::cover(const CColumnHead *c )
{
	//将第c列从列标题中删除
	c->Right->Left = c->Left;
	c->Left->Right = c->Right;
	m_master->size--;
	

	//依次处理和所有和本列相关的行
	for (CNode* columnNode = c->Down
		;columnNode != static_cast<const CNode*> (c)
		;columnNode = columnNode->Down
		)
	{

		//依次向右遍历本行的除第c列以外的的每个节点
		for (CGrid* rowNode=static_cast<CGrid*>(columnNode->Right)
			;rowNode!=columnNode
			;rowNode=static_cast<CGrid*>(rowNode->Right)
			)
		{

			//将本行的当前节点从所在列中摘除
			rowNode->Up->Down = rowNode->Down;
			rowNode->Down->Up = rowNode->Up; 
			
			rowNode->columnHead->size--;     //摘除完毕之后所在列的元素个数减1
		}
	}
}

void CExactCover::uncover(const CColumnHead *c){

	//将本列的各相关行加入到矩阵中
	for (CNode* columnNode=c->Up
		;columnNode != c
		;columnNode = columnNode->Up
		)
	{
		for (CGrid* rowNode=static_cast<CGrid*>(columnNode->Right)
			;rowNode!=columnNode
			;rowNode=static_cast<CGrid*>(rowNode->Right)
			)
		{
			//将本行的当前节点加回到原来的列中
			rowNode->Up->Down = rowNode;
			rowNode->Down->Up = rowNode; 

			rowNode->columnHead->size++;     //恢复完毕之后所在列的元素个数加1
		}
	}
	
	//把c列重新到加入列标题中
	c->Left->Right=const_cast<CColumnHead*>(c);
	c->Right->Left=const_cast<CColumnHead*>(c);  
	m_master->size++;
}

bool CExactCover::search(int k)
{
	bool flag = false;

	//矩阵为空时问题已经解决,返回true
	if (m_master->Right==m_master)
		flag =true;
	else
	{
		cover(c);
		
		for ( CGrid* row=static_cast<CGrid*>(c->Down)
			; static_cast<CNode*>(row)!= static_cast<CNode*>(const_cast<CColumnHead*>(c))
			;row=static_cast<CGrid*>(row->Down),++sublevel
			)
		{
			for(CGrid* cell=static_cast<CGrid*>(row->Right)
				;cell!=row
				;cell=static_cast<CGrid*>(cell->Right)
				)
			{
				cover(cell->columnHead);
			}

			flag =search(k+1);

			if (flag)
			{
				m_solution.insert(row->name);
				flag = true;
				break;
			}
			else
			{
				for ( CGrid* cell=static_cast<CGrid*>(row->Left)
					; cell!=row
					; cell=static_cast<CGrid*>(cell->Left)
					)
				{
					uncover(cell->columnHead);
				}
			}

		}
		if (!flag)
			uncover(c);
	}
	return flag;
}

const CColumnHead* CExactCover::selectColumn() const
{
	CColumnHead *min=static_cast<CColumnHead*>(m_master->Right);
	
	for (CColumnHead *c=min
		;c!=m_master
		;c=static_cast<CColumnHead*>(c->Right)
		)
	{
		if (c->size<min->size)
			min=c;
	}
	return min;
}

void CExactCover::print
	 (const vector<vector <int> >& matrix
	  ,ostream& os/*=log*/ 
	 )const
{
	const int elementNum = matrix[0].size();
	for(set<int>::const_iterator it = m_solution.begin()
		;it != m_solution.end() 
		;++it
		)
	{
                os << (char)('A'+*it)<<"={";
		int i=*it;
		for(int j=0;j<elementNum;++j)
			os << matrix[i][j] << ' ';
		os << "}"<<endl;
	}
}

const CColumnHead* CExactCover::getColumn( int name ) const
{
	CColumnHead* c=static_cast<CColumnHead*>(m_master->Right);
	for ( 
		; c!= m_master
		; c=static_cast<CColumnHead*>(c->Right)
		)
	{
		if (c->name==name)
			break;
	}

	return c;
}
//文件main.cpp
#include "ExactCover.h"
const int ELEMENT_NUM=7 ; //元素的个数
const int SUBSET_NUM=6;   //子集的个数

const int U[ELEMENT_NUM]={1,2,3,4,5,6,7};  //全集
const char NAMES[SUBSET_NUM]={'A','B','C','D','E','F'};  //各子集的名字
//0-1矩阵
const int Matrix[SUBSET_NUM][ELEMENT_NUM]={
	 {1,0,0,1,0,0,1}
	,{1,0,0,1,0,0,0}
	,{0,0,0,1,1,0,1}
	,{0,0,1,0,1,1,0}
	,{0,1,1,0,0,1,1}
	,{0,1,0,0,0,0,1}
};

int main(int argc,char* argv[])
{
	vector<vector <int> > M(SUBSET_NUM, vector<int>(ELEMENT_NUM));
	for(int i=0;i<SUBSET_NUM;++i)
		for(int j=0;j<ELEMENT_NUM;++j)
			M[i][j] = Matrix[i][j];

	CExactCover s(M);

	if (s.search())
		s.print(M,cout);

	system("pause");

	return 0;
}



运行结果:

B={1 0 0 1 0 0 0 }
D={0 0 1 0 1 1 0 }
F={0 1 0 0 0 0 1 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐