最小圈基问题

算法分析实验,写的有点乱,保存备用,同时供大家参考,写的不是很好,如有问题可提出交流和修改!

#include<iostream>
#include<vector>
#include<set>
using namespace std;

static int temp = 0;//在找圈方法中用于圈个数的计数
class Circle
{
public:
	Circle()
	{
		this->vertexNum = 0;
		this->circleWeight = 0;
		vertex = new pair<int, int>[10];
		circleEdge.resize(10);
	}


	int getCircleWeight()   //计算并返回圈的权
	{
		for (int i = 0; i < vertexNum; i++)
		{
			circleWeight += circleEdge[i];
		}
		return circleWeight;
	}
public:
	int vertexNum;                  //圈的顶点数
	vector<int> circleEdge;         //二维数组存储边的权
	int circleWeight;               //圈的权值
	pair<int, int> *vertex;         //存储圈的边的坐标
};

class MatrixGraphic
{
public:
	MatrixGraphic()
	{
		this->vertexNum = 0;
		this->edgeNum = 0;
		this->graphicWeight = 0;
		this->circleNum = 0;
	}

	MatrixGraphic(int verNumber, int edgNumber)
	{
		circle = new Circle[10];
		vector<vector<int>> a(verNumber);
		this->vertexNum = verNumber;
		this->edgeNum = edgNumber;
		mixCircleNum = (edgeNum + 1) - vertexNum;
		edge = a;
		for (int i = 0; i <vertexNum; i++)
			edge[i].resize(vertexNum);    //初始化邻接矩阵的大小
	}


	/*输入整个图*/
	void cinGraphic();
	/*找出所有圈并对其按照权的大小进行升序排序*/
	void fundCircle(int num1, int num2,int num3,vector<pair<int,int> > b);
	/*是否能组成圈*/
	bool isCircle(int num,vector<pair<int, int> > b);
	/*找最小圈基*/
	int fundMinCircle();
	/*判断一个圈是否是圈基中的线性组合*/
	//void isCombin(int n);

	/*是否停止向圈基中继续加圈*/
	//bool isStop(int n);

public:
	int vertexNum;				 //图的顶点数
	int edgeNum;				 //图的边数
	int graphicWeight;			 //图的权值
	vector<vector<int>> edge;	 //二维数组存储边的权
	pair<int,int> vertex[20];    //存储边的坐标
	Circle* circle;              //图中各圈
	int circleNum;               //计数器,计算圈的个数
	int mixCircleNum;            //最小圈基的范围
};

void MatrixGraphic::cinGraphic()
{
	int num = 0;
	cout << "请以"<< vertexNum <<"*"<< vertexNum <<"的邻接矩阵的形式输入图:" << endl;
	for (int i = 0; i < vertexNum; i++)
		for (int j = 0; j < vertexNum; j++)
		{
			int n;
			cin >> n;
			edge[i][j] = n;
		}
	/*存储图的边的坐标*/
	for (int i = 0; i < vertexNum; i++)
		for (int j = i; j < vertexNum; j++)
		{
			if (edge[i][j] != 0)
			{
				vertex[num].first = i;
				vertex[num].second = j;
				num++;
			}
		}
}

/*用组合算法找出n个顶点的所有组合(不考虑位置)
  num1为图的顶点个数,num2为组合的顶点个数,b为所有组合构成的集合
*/
void MatrixGraphic::fundCircle(int num1, int num2,int num3, vector<pair<int,int> > b)
{
		for (int i = num1; i >= num2; i--) 
		{
			/*找出组合*/
			b[num2 - 1] = vertex[i - 1];
			if (num2 > 1)
			{
				fundCircle(i - 1, num2 - 1, num3, b);
			}
			else 
			{
				/*如果组合能构成圈,将其放到circle中*/
				if (isCircle(num3, b)) 
				{
					for (int i = b.size() - 1; i >= 0; i--)
					{
						circle[temp].vertex[i] = b[i]; //将顶点赋值给对应的圈的顶点
						circle[temp].circleEdge[i] = edge[b[i].first][b[i].second];
					}
					circleNum += 1;
					circle[temp].vertexNum = b.size();
					++temp;
				}
			}
		}
}

/*判断是否构成圈思路:
(1)n条边能组合成圈的顶点只有n个
(2)所有边的坐标点的集合都是成对出现的,如(01 03 12 23中0 1 2 3都是成对出现的)
(3)

*/
bool MatrixGraphic::isCircle(int num, vector<pair<int, int> > b)
{
	vector<int> ver;
	set<int>s0;
	set<int>s1;
	set<int>s2;
	int n = 0;
	for (int i = 0; i < b.size(); i++)
	{
		s0.insert(b[i].first);
	}
	for (int i = 0; i < b.size(); i++)
	{
		s1.insert(b[i].second);
	}
	for (int i = 0; i < b.size(); i++)
	{
		ver.push_back(b[i].first);
		ver.push_back(b[i].second);
		s2.insert(b[i].first);
		s2.insert(b[i].second);
	}
	/*n条边能组合成圈的顶点只有n个,且都是成对出现的(有且只有两个)*/
	for (int i = 0; i < b.size() * 2; i++)
	{
		for (int j = 0; j < b.size() * 2; j++)
		{
			if (ver[i] == ver[j])
				n += 1;
		}
		if (n > 2)
			return false;
		else
		{
			n = 0;
		}
	}
	if (s2.size() == num && s0.size() == (num - 1) && s1.size() == (num - 1) )
		return true;
	else
		return false;
}

/*找最小圈基的思路:
对排好序的圈挨个放进圈基,如果圈是圈基的线性组合(即圈的所有边在圈基中都可以找到),删掉
直到圈基中圈的个数满足要求停止加圈
*/
int MatrixGraphic::fundMinCircle()
{
	static int temp1 = 2;
	int minCircle = 0;  //最小圈基的权
	set<pair<int,int> >MySet;
	Circle *Mycircle = new Circle[mixCircleNum];
	for (int i = 0; i < circleNum; i++)
	{
		if (i < 2)
		{
			Mycircle[i] = circle[i];
		}
		else
		{
			/*先把所有的边放到集合set中*/
			for (int a = 0; a < i; a++)
			{
				for (int b = 0; b < circle[a].vertexNum; b++)
				{
					MySet.insert(Mycircle[a].vertex[b]);
				}
			}
			temp = 0;
			for (int j = 0; j < circle[i].vertexNum; j++)//检验第i是否是组合成的,分别扫描它的所有顶点
			{
				if (MySet.find(circle[i].vertex[j])!=MySet.end())
				{
					temp += 1;
				}
			}
			if (temp != circle[i].vertexNum)
			{
				Mycircle[temp1] = circle[i];
				temp1++;
			}
			if (temp1 == (mixCircleNum))
				break;
			MySet.clear();
		}
		
	}
	for (int i = 0; i < mixCircleNum; i++)
	{
		minCircle += Mycircle[i].circleWeight;
	}
	/*输出最小圈基*/
	cout <<endl<< "最小圈基:" << endl;
	for (int i = 0; i < mixCircleNum; i++)
	{
		for (int j = 0; j < Mycircle[i].vertexNum; j++)
		{
			cout << Mycircle[i].vertex[j].first << Mycircle[i].vertex[j].second << " ";
		}
		cout << endl;
	}
	return minCircle;
}
int main()
{
	int e, v;                                     //存储图的顶点和边
	cout << "请输入图的顶点和边数:" << endl;
	cin >> e >> v;
	MatrixGraphic MyGraphic(e,v);                 //定义一个图对象
	MyGraphic.cinGraphic();                       //调用cinGraphic()方法,以邻接矩阵的形式输入整个图

	//找到所有的圈
	/*找圈的思路:
		(1)3个或3个以上的顶点可构成圈,找出可以构成圈的所有可能的顶点组合
		(2)从找出的组合中再筛选出真正能构成圈的
	*/
	for (int i = 3; i <= v; i++)
	{
		vector<pair<int, int> > b(i);
		MyGraphic.fundCircle(v, i,i, b);//fundCircle方法用到了排列组合
	}

	cout << "输出图中所有圈的权:" << endl;
	for (int i = 0; i < MyGraphic.circleNum; i++)
	{
		MyGraphic.circle[i].getCircleWeight();  //计算圈的权
		cout << MyGraphic.circle[i].circleWeight << "  ";
	}	
	/*对所有圈按照升序排列*/
	Circle MyCircl;
	for (int i = 0; i < MyGraphic.circleNum - 1; i++)
	{
		for (int j = i+1; j < MyGraphic.circleNum ; j++)
		if (MyGraphic.circle[i].circleWeight > MyGraphic.circle[j].circleWeight)
		{
			MyCircl = MyGraphic.circle[i];
			MyGraphic.circle[i] = MyGraphic.circle[j];
			MyGraphic.circle[j] = MyCircl;
		}
	}
	cout << endl;
	cout << "排序后的圈的权:" << endl;
	for (int i = 0; i < MyGraphic.circleNum; i++)
	{
		//MyGraphic.circle[i].getCircleWeight();
		cout << MyGraphic.circle[i].circleWeight << "  ";
	}

	cout<<endl<<"最小圈基的权:"<<MyGraphic.fundMinCircle()<<endl;//调用fundMinCircle()方法,输出最小圈基和它的权
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值